import pytest
import platform
from pathlib import Path
from datetime import datetime
from flexoentity import Domain, FlexoSignature, DomainManager, EntityRegistry, CompositeBackend, InMemoryBackend
from flexoentity import get_signing_backend, CertificateReference


@pytest.fixture
def fixed_datetime(monkeypatch):
    class FixedDate(datetime):
        @classmethod
        def now(cls, tz=None):
            return datetime(2025, 11, 1, tzinfo=tz)
    monkeypatch.setattr("flexoentity.id_factory.datetime", FixedDate)
    return FixedDate


@pytest.fixture
def sample_domain():
    domain_id = "PY_ARITHM"
    return Domain.with_domain_id(domain_id=domain_id,
                                 fullname="PYTHON_ARITHMETIC",
                                 description="ALL ABOUT ARITHMETIC IN PYTHON")


SYSTEM = platform.system()

@pytest.fixture
def local_backend():
    return InMemoryBackend(Domain)

@pytest.fixture
def staging_backend():
    return InMemoryBackend(Domain)

@pytest.fixture
def permanent_backend():
    return InMemoryBackend(Domain)

@pytest.fixture
def sample_domain_manager(local_backend, staging_backend, permanent_backend):
    return DomainManager(local_backend=local_backend,
                         staging_backend=staging_backend,
                         permanent_backend=CompositeBackend(authoritative_backend=permanent_backend,
                                                            sync_backends=None),
                         registry=EntityRegistry())

# ─────────────────────────────────────────────────────────────
# Basic test data directory + PEM test files
# ─────────────────────────────────────────────────────────────


@pytest.fixture(scope="session")
def test_data_dir():
    return Path(__file__).parent / "data"


@pytest.fixture(scope="session")
def test_cert(test_data_dir):
    return test_data_dir / "testcert.pem"


@pytest.fixture(scope="session")
def test_key(test_data_dir):
    return test_data_dir / "testkey.pem"


# ─────────────────────────────────────────────────────────────
# CertificateReference fixtures for each platform
# ─────────────────────────────────────────────────────────────

@pytest.fixture(scope="session")
def cert_ref_linux(test_cert, test_key):
    """Linux: Uses OpenSSL CMS with PEM cert + PEM private key."""
    return CertificateReference(
        platform="LINUX",
        identifier=str(test_cert),
        private_key_path=str(test_key),
        public_cert_path=str(test_cert),
    )


@pytest.fixture(scope="session")
def cert_ref_macos(test_cert):
    """
    macOS: Uses Keychain identity with Common Name (CN).
    The test cert must be imported into the login keychain with CN=FlexOSignerTest.
    """
    return CertificateReference(
        platform="MACOS",
        identifier="FlexOSignerTest",
        public_cert_path=str(test_cert),
    )


@pytest.fixture(scope="session")
def signing_backend(test_cert, test_key):
    """Return the correct backend for the current platform."""

    if SYSTEM == "Linux":
        cert_ref = CertificateReference(
            platform="LINUX",
            identifier=str(test_cert),
            private_key_path=str(test_key),
            public_cert_path=str(test_cert),
        )

    elif SYSTEM == "Darwin":
        cert_ref = CertificateReference(
            platform="MACOS",
            identifier="FlexOSignerTest",
            public_cert_path=str(test_cert),
        )

    elif SYSTEM == "Windows":
        pytest.skip("Windows signing tests not implemented yet")

    else:
        pytest.skip(f"Unsupported platform: {SYSTEM}")

    try:
        backend = get_signing_backend(cert_ref)
        # sanity check: ensures cert exists and command is available
        _ = backend.certificate_thumbprint
        return backend
    except Exception as e:
        pytest.skip(f"Backend unavailable or misconfigured: {e}")


@pytest.fixture
def sample_signature(sample_domain, cert_ref_linux):
    return FlexoSignature.with_domain_id(domain_id="SIG", signed_entity=sample_domain,
                                         certificate_reference=cert_ref_linux,
                                         comment="This is a mock signature")
