import base64
from pathlib import Path

import pytest
from cryptography.hazmat.primitives import serialization
from cryptography.x509.base import load_pem_x509_certificate
from pytest import raises

from pyattest.attestation import Attestation
from pyattest.configs.google import GoogleConfig
from pyattest.exceptions import (
    InvalidKeyIdException,
    InvalidCtsProfile,
    InvalidBasicIntegrity,
    InvalidCertificateChainException,
    InvalidAppIdException,
)
import os

from pyattest.testutils.factories.attestation import google as google_factory

root_cn = "pyattest-testing-leaf.ch"
root_ca = load_pem_x509_certificate(
    Path("pyattest/testutils/fixtures/root_cert.pem").read_bytes()
)
root_ca_pem = root_ca.public_bytes(serialization.Encoding.PEM)
nonce = os.urandom(32)


@pytest.mark.asyncio
async def test_happy_path():
    """Test the basic attest verification where everything works like it should :)"""
    attest, key_id = google_factory.get(apk_package_name="foo", nonce=nonce)
    config = GoogleConfig(
        key_ids=[base64.b64encode(key_id)],
        apk_package_name="foo",
        root_cn=root_cn,
        root_ca=root_ca_pem,
        production=False,
    )

    attestation = Attestation(attest, nonce, config)
    await attestation.verify()


@pytest.mark.asyncio
async def test_key_id():
    attest, key_id = google_factory.get(apk_package_name="foo", nonce=nonce)
    config = GoogleConfig(
        key_ids=[base64.b64encode(b"100%wrong")],
        apk_package_name="foo",
        root_cn=root_cn,
        root_ca=root_ca_pem,
        production=False,
    )

    attestation = Attestation(attest, nonce, config)

    with raises(InvalidKeyIdException):
        await attestation.verify()


@pytest.mark.asyncio
async def test_cts_profile():
    attest, key_id = google_factory.get(
        apk_package_name="foo", nonce=nonce, cts_profile=False
    )
    config = GoogleConfig(
        key_ids=[base64.b64encode(key_id)],
        apk_package_name="foo",
        root_cn=root_cn,
        root_ca=root_ca_pem,
        production=True,
    )

    attestation = Attestation(attest, nonce, config)

    with raises(InvalidCtsProfile):
        await attestation.verify()


@pytest.mark.asyncio
async def test_basic_integrity():
    attest, key_id = google_factory.get(
        apk_package_name="foo", nonce=nonce, basic_integrity=False
    )
    config = GoogleConfig(
        key_ids=[base64.b64encode(key_id)],
        apk_package_name="foo",
        root_cn=root_cn,
        root_ca=root_ca_pem,
        production=True,
    )

    attestation = Attestation(attest, nonce, config)

    with raises(InvalidBasicIntegrity):
        await attestation.verify()


@pytest.mark.asyncio
async def test_apk_package_name():
    attest, key_id = google_factory.get(apk_package_name="foo", nonce=nonce)
    config = GoogleConfig(
        key_ids=[base64.b64encode(key_id)],
        apk_package_name="bar",
        root_cn=root_cn,
        root_ca=root_ca_pem,
        production=True,
    )

    attestation = Attestation(attest, nonce, config)

    with raises(InvalidAppIdException):
        await attestation.verify()


@pytest.mark.asyncio
async def test_certificate_chain():
    attest, key_id = google_factory.get(apk_package_name="foo", nonce=nonce)
    config = GoogleConfig(
        key_ids=[base64.b64encode(key_id)],
        apk_package_name="bar",
        root_cn=root_cn,
        production=True,
    )

    attestation = Attestation(attest, nonce, config)

    with raises(InvalidCertificateChainException):
        await attestation.verify()
