"""Tests for Passports models."""

from __future__ import annotations

from ai4gh.specs.passports.models import (
    AccessDecision,
    PassportClaims,
    VisaAssertionSource,
    VisaClaim,
    VisaType,
)


class TestVisaType:
    def test_enum_values(self) -> None:
        assert VisaType.AFFILIATION_AND_ROLE == "AffiliationAndRole"
        assert VisaType.CONTROLLED_ACCESS_GRANTS == "ControlledAccessGrants"
        assert VisaType.LINKED_IDENTITIES == "LinkedIdentities"
        assert VisaType.RESEARCHER_STATUS == "ResearcherStatus"
        assert VisaType.ACCEPTED_TERMS_AND_POLICIES == "AcceptedTermsAndPolicies"


class TestVisaAssertionSource:
    def test_enum_values(self) -> None:
        assert VisaAssertionSource.SO == "so"
        assert VisaAssertionSource.SYSTEM == "system"


class TestVisaClaim:
    def test_minimal(self) -> None:
        visa = VisaClaim(
            type=VisaType.RESEARCHER_STATUS,
            value="https://example.com/researcher",
            source="https://idp.example.com",
        )
        assert visa.type is VisaType.RESEARCHER_STATUS
        assert visa.by is None

    def test_full(self) -> None:
        visa = VisaClaim(
            type=VisaType.CONTROLLED_ACCESS_GRANTS,
            value="https://dataset.example.com/ds001",
            source="https://dac.example.com",
            by=VisaAssertionSource.SO,
            asserted=1704067200,
            conditions=[[{"type": "AffiliationAndRole"}]],
        )
        assert visa.by is VisaAssertionSource.SO
        assert visa.asserted == 1704067200
        assert len(visa.conditions) == 1

    def test_from_dict(self) -> None:
        visa = VisaClaim.model_validate(
            {
                "type": "ResearcherStatus",
                "value": "https://example.com",
                "source": "https://idp.example.com",
            }
        )
        assert visa.type is VisaType.RESEARCHER_STATUS


class TestPassportClaims:
    def test_minimal(self) -> None:
        claims = PassportClaims()
        assert claims.iss is None
        assert claims.ga4gh_passport_v1 is None

    def test_full(self) -> None:
        claims = PassportClaims(
            iss="https://idp.example.com",
            sub="user@example.com",
            exp=1704153600,
            iat=1704067200,
            jti="unique-id",
            scope="openid ga4gh_passport_v1",
            ga4gh_passport_v1=[
                VisaClaim(
                    type=VisaType.RESEARCHER_STATUS,
                    value="https://example.com",
                    source="https://idp.example.com",
                )
            ],
        )
        assert claims.iss == "https://idp.example.com"
        assert len(claims.ga4gh_passport_v1) == 1


class TestAccessDecision:
    def test_granted(self) -> None:
        decision = AccessDecision(
            granted=True,
            reason="Found matching visa",
            matching_visas=[
                VisaClaim(
                    type=VisaType.CONTROLLED_ACCESS_GRANTS,
                    value="ds001",
                    source="https://dac.example.com",
                )
            ],
        )
        assert decision.granted is True
        assert len(decision.matching_visas) == 1

    def test_denied(self) -> None:
        decision = AccessDecision(
            granted=False,
            reason="No matching visa found",
        )
        assert decision.granted is False
        assert decision.matching_visas is None
