"""Tests for VCard model implementation."""

from datetime import datetime, timedelta

import pytest

from mcard.model.dots import CardPlane, DOTSRole, EOSRole
from mcard.model.vcard import (
    Capability,
    CapabilityScope,
    ExternalRef,
    GatekeeperDirection,
    VCard,
)


class TestVCardInitialization:
    """Test VCard initialization and basic properties."""

    def test_vcard_creation(self):
        """Test basic VCard creation."""
        vcard = VCard(
            subject_did="did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK",
            controller_pubkeys=["pubkey1", "pubkey2"],
        )

        assert (
            vcard.subject_did
            == "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK"
        )
        assert len(vcard.controller_pubkeys) == 2
        assert vcard.hash is not None

    def test_vcard_dots_metadata(self):
        """Test DOTS metadata for VCard."""
        vcard = VCard(subject_did="did:key:test", controller_pubkeys=["pubkey1"])

        meta = vcard.get_dots_metadata()
        assert meta.role == DOTSRole.ARENA
        assert meta.plane == CardPlane.APPLICATION
        assert meta.eos_role == EOSRole.SOVEREIGN_DECISION


class TestCapabilities:
    """Test capability management."""

    def test_add_capability(self):
        """Test adding a capability."""
        vcard = VCard(subject_did="did:key:owner", controller_pubkeys=["pubkey1"])

        cap = Capability(
            capability_id="cap1",
            actor_did="did:key:actor1",
            scope=CapabilityScope.READ,
            resource_pattern=".*",
        )

        vcard.add_capability(cap)
        assert len(vcard.get_valid_capabilities()) == 1

    def test_capability_expiry(self):
        """Test capability expiration."""
        vcard = VCard(subject_did="did:key:owner", controller_pubkeys=["pubkey1"])

        expired_cap = Capability(
            capability_id="expired",
            actor_did="did:key:actor1",
            scope=CapabilityScope.READ,
            resource_pattern=".*",
            expires_at=datetime.now() - timedelta(hours=1),
        )

        valid_cap = Capability(
            capability_id="valid",
            actor_did="did:key:actor2",
            scope=CapabilityScope.WRITE,
            resource_pattern=".*",
            expires_at=datetime.now() + timedelta(hours=1),
        )

        vcard.add_capability(expired_cap)
        vcard.add_capability(valid_cap)

        valid_caps = vcard.get_valid_capabilities()
        assert len(valid_caps) == 1
        assert valid_caps[0].capability_id == "valid"

    def test_has_capability(self):
        """Test capability check for resource."""
        vcard = VCard(subject_did="did:key:owner", controller_pubkeys=["pubkey1"])

        cap = Capability(
            capability_id="cap1",
            actor_did="did:key:actor1",
            scope=CapabilityScope.READ,
            resource_pattern="^abc.*",  # Matches resources starting with "abc"
        )

        vcard.add_capability(cap)

        assert vcard.has_capability(CapabilityScope.READ, "abc123")
        assert not vcard.has_capability(CapabilityScope.READ, "xyz123")
        assert not vcard.has_capability(CapabilityScope.WRITE, "abc123")


class TestGatekeeper:
    """Test ingress/egress gatekeeper functionality."""

    def test_authorize_ingress(self):
        """Test ingress authorization."""
        vcard = VCard(subject_did="did:key:owner", controller_pubkeys=["pubkey1"])

        # Add write capability for the actor
        cap = Capability(
            capability_id="write_cap",
            actor_did="did:key:sender",
            scope=CapabilityScope.WRITE,
            resource_pattern=".*",
        )
        vcard.add_capability(cap)

        # Authorized ingress
        assert vcard.authorize_ingress("did:key:sender", "hash123")

        # Unauthorized actor
        assert not vcard.authorize_ingress("did:key:unknown", "hash456")

        # Check audit log
        log = vcard.get_gatekeeper_log(GatekeeperDirection.INGRESS)
        assert len(log) == 2
        assert log[0].authorized is True
        assert log[1].authorized is False

    def test_authorize_egress_requires_registration(self):
        """Test that egress requires prior registration."""
        vcard = VCard(subject_did="did:key:owner", controller_pubkeys=["pubkey1"])

        cap = Capability(
            capability_id="read_cap",
            actor_did="did:key:owner",
            scope=CapabilityScope.READ,
            resource_pattern=".*",
        )
        vcard.add_capability(cap)

        # Try egress without registration - should fail
        assert not vcard.authorize_egress("did:key:receiver", "hash123")

        # Register for egress
        vcard.register_for_egress("hash123")

        # Now egress should succeed
        assert vcard.authorize_egress("did:key:receiver", "hash123")

        # Check audit log
        log = vcard.get_gatekeeper_log(GatekeeperDirection.EGRESS)
        assert len(log) == 2
        assert log[0].authorized is False  # Before registration
        assert log[1].authorized is True  # After registration


class TestExternalRefs:
    """Test external reference management."""

    def test_add_external_ref(self):
        """Test adding external references."""
        vcard = VCard(subject_did="did:key:owner", controller_pubkeys=["pubkey1"])

        ref = ExternalRef(
            uri="https://example.com/data", content_hash="hash123", status="pending"
        )

        vcard.add_external_ref(ref)

        pending = vcard.get_external_refs_by_status("pending")
        assert len(pending) == 1
        assert pending[0].uri == "https://example.com/data"

    def test_verify_external_ref(self):
        """Test external reference verification."""
        vcard = VCard(subject_did="did:key:owner", controller_pubkeys=["pubkey1"])

        ref = ExternalRef(
            uri="https://example.com/data", content_hash="hash123", status="pending"
        )
        vcard.add_external_ref(ref)

        # Verify with correct hash
        assert vcard.verify_external_ref("https://example.com/data", "hash123")
        assert vcard.get_external_refs_by_status("verified")[0].status == "verified"

        # Verify with incorrect hash
        vcard.add_external_ref(
            ExternalRef(
                uri="https://example.com/other",
                content_hash="original",
                status="pending",
            )
        )
        assert not vcard.verify_external_ref("https://example.com/other", "changed")
        assert vcard.get_external_refs_by_status("stale")[0].status == "stale"


class TestPCardReferences:
    """Test PCard reference management."""

    def test_add_pcard_reference(self):
        """Test adding PCard references."""
        vcard = VCard(subject_did="did:key:owner", controller_pubkeys=["pubkey1"])

        vcard.add_pcard_reference("pcard_hash_1")
        vcard.add_pcard_reference("pcard_hash_2")

        refs = vcard.get_pcard_references()
        assert len(refs) == 2
        assert "pcard_hash_1" in refs
        assert "pcard_hash_2" in refs


class TestSimulationMode:
    """Test EOS-compliant simulation mode."""

    def test_simulation_context(self):
        """Test simulation mode creates isolated context."""
        vcard = VCard(subject_did="did:key:owner", controller_pubkeys=["pubkey1"])

        sim = vcard.simulate_mode()

        sim.log_effect("file_write", {"path": "/test/file.txt", "content": "hello"})
        sim.log_effect("network_request", {"url": "https://api.example.com"})

        log = sim.get_simulation_log()
        assert len(log) == 2
        assert all(entry["simulated"] is True for entry in log)


if __name__ == "__main__":
    pytest.main([__file__, "-v"])
