import base64
import datetime
import pytest

from mock import MagicMock


from ansible.module_utils.acme import (
    HAS_CURRENT_CRYPTOGRAPHY,
    nopad_b64,
    write_file,
    read_file,
    pem_to_der,
    _parse_key_openssl,
    # _sign_request_openssl,
    _parse_key_cryptography,
    # _sign_request_cryptography,
    cryptography_get_csr_domains,
    cryptography_get_cert_days,
)

################################################

NOPAD_B64 = [
    ("", ""),
    ("\n", "Cg"),
    ("123", "MTIz"),
    ("Lorem?ipsum", "TG9yZW0_aXBzdW0"),
]


@pytest.mark.parametrize("value, result", NOPAD_B64)
def test_nopad_b64(value, result):
    assert nopad_b64(value.encode('utf-8')) == result


################################################

TEST_TEXT = r"""1234
5678"""


def test_read_file(tmpdir):
    fn = tmpdir / 'test.txt'
    fn.write(TEST_TEXT)
    assert read_file(str(fn), 't') == TEST_TEXT
    assert read_file(str(fn), 'b') == TEST_TEXT.encode('utf-8')


def test_write_file(tmpdir):
    fn = tmpdir / 'test.txt'
    module = MagicMock()
    write_file(module, str(fn), TEST_TEXT.encode('utf-8'))
    assert fn.read() == TEST_TEXT


################################################

TEST_PEM_DERS = [
    (
        r"""
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIDWajU0PyhYKeulfy/luNtkAve7DkwQ01bXJ97zbxB66oAoGCCqGSM49
AwEHoUQDQgAEAJz0yAAXAwEmOhTRkjXxwgedbWO6gobYM3lWszrS68G8QSzhXR6A
mQ3IzZDimnTTXO7XhVylDT8SLzE44/Epmw==
-----END EC PRIVATE KEY-----
""",
        base64.b64decode('MHcCAQEEIDWajU0PyhYKeulfy/luNtkAve7DkwQ01bXJ97zbxB66oAo'
                         'GCCqGSM49AwEHoUQDQgAEAJz0yAAXAwEmOhTRkjXxwgedbWO6gobYM3'
                         'lWszrS68G8QSzhXR6AmQ3IzZDimnTTXO7XhVylDT8SLzE44/Epmw==')
    )
]


@pytest.mark.parametrize("pem, der", TEST_PEM_DERS)
def test_pem_to_der(pem, der, tmpdir):
    fn = tmpdir / 'test.pem'
    fn.write(pem)
    assert pem_to_der(str(fn)) == der


################################################

TEST_KEYS = [
    (
        r"""
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIDWajU0PyhYKeulfy/luNtkAve7DkwQ01bXJ97zbxB66oAoGCCqGSM49
AwEHoUQDQgAEAJz0yAAXAwEmOhTRkjXxwgedbWO6gobYM3lWszrS68G8QSzhXR6A
mQ3IzZDimnTTXO7XhVylDT8SLzE44/Epmw==
-----END EC PRIVATE KEY-----
""",
        {
            'alg': 'ES256',
            'hash': 'sha256',
            'jwk': {
                'crv': 'P-256',
                'kty': 'EC',
                'x': 'AJz0yAAXAwEmOhTRkjXxwgedbWO6gobYM3lWszrS68E',
                'y': 'vEEs4V0egJkNyM2Q4pp001zu14VcpQ0_Ei8xOOPxKZs',
            },
            'point_size': 32,
            'type': 'ec',
        },
        r"""
read EC key
Private-Key: (256 bit)
priv:
    35:9a:8d:4d:0f:ca:16:0a:7a:e9:5f:cb:f9:6e:36:
    d9:00:bd:ee:c3:93:04:34:d5:b5:c9:f7:bc:db:c4:
    1e:ba
pub:
    04:00:9c:f4:c8:00:17:03:01:26:3a:14:d1:92:35:
    f1:c2:07:9d:6d:63:ba:82:86:d8:33:79:56:b3:3a:
    d2:eb:c1:bc:41:2c:e1:5d:1e:80:99:0d:c8:cd:90:
    e2:9a:74:d3:5c:ee:d7:85:5c:a5:0d:3f:12:2f:31:
    38:e3:f1:29:9b
ASN1 OID: prime256v1
NIST CURVE: P-256
"""
    )
]


@pytest.mark.parametrize("pem, result, openssl_output", TEST_KEYS)
def test_eckeyparse_openssl(pem, result, openssl_output, tmpdir):
    fn = tmpdir / 'test.key'
    fn.write(pem)
    module = MagicMock()
    module.run_command = MagicMock(return_value=(0, openssl_output, 0))
    error, key = _parse_key_openssl('openssl', module, key_file=str(fn))
    assert error is None
    key.pop('key_file')
    assert key == result


if HAS_CURRENT_CRYPTOGRAPHY:
    @pytest.mark.parametrize("pem, result, dummy", TEST_KEYS)
    def test_eckeyparse_cryptography(pem, result, dummy):
        module = MagicMock()
        error, key = _parse_key_cryptography(module, key_content=pem)
        assert error is None
        key.pop('key_obj')
        assert key == result


################################################

TEST_CSR = r"""
-----BEGIN NEW CERTIFICATE REQUEST-----
MIIBJTCBzQIBADAWMRQwEgYDVQQDEwthbnNpYmxlLmNvbTBZMBMGByqGSM49AgEG
CCqGSM49AwEHA0IABACc9MgAFwMBJjoU0ZI18cIHnW1juoKG2DN5VrM60uvBvEEs
4V0egJkNyM2Q4pp001zu14VcpQ0/Ei8xOOPxKZugVTBTBgkqhkiG9w0BCQ4xRjBE
MCMGA1UdEQQcMBqCC2V4YW1wbGUuY29tggtleGFtcGxlLm9yZzAMBgNVHRMBAf8E
AjAAMA8GA1UdDwEB/wQFAwMHgAAwCgYIKoZIzj0EAwIDRwAwRAIgcDyoRmwFVBDl
FvbFZtiSd5wmJU1ltM6JtcfnLWnjY54CICruOByrropFUkOKKb4xXOYsgaDT93Wr
URnCJfTLr2T3
-----END NEW CERTIFICATE REQUEST-----
"""


if HAS_CURRENT_CRYPTOGRAPHY:
    def test_csrdomains_cryptography(tmpdir):
        fn = tmpdir / 'test.csr'
        fn.write(TEST_CSR)
        module = MagicMock()
        domains = cryptography_get_csr_domains(module, str(fn))
        assert domains == set(['ansible.com', 'example.com', 'example.org'])


################################################

TEST_CERT = r"""
-----BEGIN CERTIFICATE-----
MIIBljCCATugAwIBAgIBATAKBggqhkjOPQQDAjAWMRQwEgYDVQQDEwthbnNpYmxl
LmNvbTAeFw0xODExMjUxNTI4MjNaFw0xODExMjYxNTI4MjRaMBYxFDASBgNVBAMT
C2Fuc2libGUuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEAJz0yAAXAwEm
OhTRkjXxwgedbWO6gobYM3lWszrS68G8QSzhXR6AmQ3IzZDimnTTXO7XhVylDT8S
LzE44/Epm6N6MHgwIwYDVR0RBBwwGoILZXhhbXBsZS5jb22CC2V4YW1wbGUub3Jn
MAwGA1UdEwEB/wQCMAAwDwYDVR0PAQH/BAUDAweAADATBgNVHSUEDDAKBggrBgEF
BQcDATAdBgNVHQ4EFgQUmNL9PMzNaUX74owwLFRiGDS3B3MwCgYIKoZIzj0EAwID
SQAwRgIhALz7Ur96ky0OfM5D9MwFmCg2jccqm/UglGI9+4KeOEIyAiEAwFX4tdll
QSrd1HY/jMsHwdK5wH3JkK/9+fGwyRP11VI=
-----END CERTIFICATE-----
"""

TEST_CERT_DAYS = [
    (datetime.datetime(2018, 11, 15, 1, 2, 3), 11),
    (datetime.datetime(2018, 11, 25, 15, 20, 0), 1),
    (datetime.datetime(2018, 11, 25, 15, 30, 0), 0),
]


if HAS_CURRENT_CRYPTOGRAPHY:
    @pytest.mark.parametrize("now, expected_days", TEST_CERT_DAYS)
    def test_certdays_cryptography(now, expected_days, tmpdir):
        fn = tmpdir / 'test-cert.pem'
        fn.write(TEST_CERT)
        module = MagicMock()
        days = cryptography_get_cert_days(module, str(fn), now=now)
        assert days == expected_days