from __future__ import annotations

import unittest

from govoplan_core.core.modules import ModuleContext, ModuleManifest
from govoplan_core.core.policy import (
    CAPABILITY_POLICY_SCHEDULING_PARTICIPANT_PRIVACY,
    PolicySourceStep,
    SchedulingParticipantPrivacyDecision,
    SchedulingParticipantPrivacyPolicy,
    SchedulingParticipantPrivacyRequest,
    scheduling_participant_privacy_policy,
)
from govoplan_core.core.registry import PlatformRegistry


class _PrivacyPolicy:
    def resolve_scheduling_participant_visibility(
        self,
        session: object,
        *,
        request: SchedulingParticipantPrivacyRequest,
    ) -> SchedulingParticipantPrivacyDecision:
        del session
        return SchedulingParticipantPrivacyDecision(
            effective_visibility="aggregates_only",
            reason=f"Participant roster is restricted for {request.scheduling_request_id}.",
            details={"requested_visibility": request.requested_visibility},
        )


class SchedulingPrivacyContractTests(unittest.TestCase):
    def test_capability_name_and_request_context_are_stable(self) -> None:
        self.assertEqual(
            CAPABILITY_POLICY_SCHEDULING_PARTICIPANT_PRIVACY,
            "policy.schedulingParticipantPrivacy",
        )
        request = SchedulingParticipantPrivacyRequest(
            tenant_id="tenant-1",
            scheduling_request_id="request-1",
            participant_id="participant-1",
            actor_user_id="user-1",
            requested_visibility="names_and_statuses",
            context={"request_status": "open"},
        )

        self.assertEqual(request.requested_visibility, "names_and_statuses")
        self.assertEqual(request.context["request_status"], "open")

    def test_decision_serializes_policy_provenance(self) -> None:
        decision = SchedulingParticipantPrivacyDecision(
            effective_visibility="aggregates_only",
            reason="Tenant privacy policy restricts the participant roster.",
            source_path=(
                PolicySourceStep(
                    scope_type="tenant",
                    scope_id="tenant-1",
                    label="Tenant",
                    applied_fields=("scheduling_participant_visibility",),
                ),
            ),
            details={"requested_visibility": "names_and_statuses"},
        )

        payload = decision.to_dict()
        self.assertEqual(payload["effective_visibility"], "aggregates_only")
        self.assertEqual(payload["source_path"][0]["path"], "tenant:tenant-1")
        self.assertEqual(payload["details"]["requested_visibility"], "names_and_statuses")

    def test_optional_provider_resolves_through_platform_registry(self) -> None:
        provider = _PrivacyPolicy()
        self.assertIsInstance(provider, SchedulingParticipantPrivacyPolicy)

        registry = PlatformRegistry()
        registry.register(
            ModuleManifest(
                id="policy_test",
                name="Policy test",
                version="test",
                capability_factories={
                    CAPABILITY_POLICY_SCHEDULING_PARTICIPANT_PRIVACY: lambda context: provider,
                },
            ),
        )
        registry.configure_capability_context(ModuleContext(registry=registry, settings=object()))

        self.assertIs(scheduling_participant_privacy_policy(registry), provider)

    def test_optional_provider_lookup_does_not_choose_a_fallback(self) -> None:
        self.assertIsNone(scheduling_participant_privacy_policy(None))
        self.assertIsNone(scheduling_participant_privacy_policy(PlatformRegistry()))


if __name__ == "__main__":
    unittest.main()
