from __future__ import annotations

import unittest
from unittest.mock import MagicMock, patch

from govoplan_core.celery_app import celery, expire_idm_assignments
from govoplan_core.core.idm import (
    CAPABILITY_IDM_ASSIGNMENT_LIFECYCLE,
    IdmAssignmentLifecycle,
    idm_assignment_lifecycle,
)
from govoplan_core.core.modules import ModuleContext, ModuleManifest
from govoplan_core.core.registry import PlatformRegistry


class _Lifecycle:
    def process_expired(
        self,
        session,
        *,
        tenant_id=None,
        effective_at=None,
        limit=100,
    ):
        del session, tenant_id, effective_at, limit
        return {"selected": 0, "expired": 0, "assignment_ids": []}


class IdmAssignmentLifecycleWorkerTests(unittest.TestCase):
    def test_contract_is_runtime_checkable_and_optional(self) -> None:
        provider = _Lifecycle()
        self.assertIsInstance(provider, IdmAssignmentLifecycle)
        registry = PlatformRegistry()
        registry.register(
            ModuleManifest(
                id="idm_lifecycle_test",
                name="IDM lifecycle test",
                version="test",
                capability_factories={
                    CAPABILITY_IDM_ASSIGNMENT_LIFECYCLE: (
                        lambda _context: provider
                    )
                },
            )
        )
        registry.configure_capability_context(
            ModuleContext(registry=registry, settings=object())
        )

        self.assertIs(provider, idm_assignment_lifecycle(registry))
        self.assertIsNone(idm_assignment_lifecycle(PlatformRegistry()))

    def test_worker_commits_provider_outcome(self) -> None:
        session = MagicMock()
        database = MagicMock()
        database.SessionLocal.return_value.__enter__.return_value = session
        provider = MagicMock()
        provider.process_expired.return_value = {
            "selected": 2,
            "expired": 1,
            "assignment_ids": ["assignment-1"],
        }

        with (
            patch(
                "govoplan_core.celery_app._idm_assignment_lifecycle",
                return_value=provider,
            ),
            patch(
                "govoplan_core.db.session.get_database",
                return_value=database,
            ),
        ):
            result = expire_idm_assignments.run("tenant-1", 25)

        provider.process_expired.assert_called_once_with(
            session,
            tenant_id="tenant-1",
            limit=25,
        )
        session.commit.assert_called_once_with()
        self.assertEqual(1, result["expired"])

    def test_route_and_periodic_job_are_registered(self) -> None:
        self.assertEqual(
            {"queue": "idm"},
            celery.conf.task_routes["govoplan.idm.expire_assignments"],
        )
        schedule = celery.conf.beat_schedule[
            "idm-assignment-expiry-every-minute"
        ]
        self.assertEqual("govoplan.idm.expire_assignments", schedule["task"])
        self.assertEqual(60.0, schedule["schedule"])


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