from __future__ import annotations

import unittest

from govoplan_core.core.modules import ModuleContext, ModuleManifest
from govoplan_core.core.people import (
    CAPABILITY_ACCESS_PEOPLE_SEARCH,
    CAPABILITY_ADDRESSES_PEOPLE_SEARCH,
    PeopleSearchGroup,
    PersonSearchCandidate,
    people_search_providers,
    person_selection_key,
    search_visible_people,
)
from govoplan_core.core.registry import PlatformRegistry


class FakePeopleSearchProvider:
    def __init__(self, *groups: PeopleSearchGroup) -> None:
        self.groups = groups
        self.calls: list[tuple[object, object, str, int]] = []

    def search_people(self, session: object, principal: object, *, query: str, limit: int = 25):
        self.calls.append((session, principal, query, limit))
        return self.groups


class PeopleSearchContractTests(unittest.TestCase):
    def test_collects_optional_providers_in_stable_group_order(self) -> None:
        duplicate = PersonSearchCandidate(
            selection_key="account:1",
            kind="account",
            reference_id="1",
            display_name="Ada Lovelace",
        )
        access = FakePeopleSearchProvider(PeopleSearchGroup(key="accounts", label="Accounts", candidates=(duplicate, duplicate)))
        addresses = FakePeopleSearchProvider(
            PeopleSearchGroup(
                key="contacts",
                label="Contacts",
                candidates=(
                    PersonSearchCandidate(
                        selection_key="contact:2:ada@example.test",
                        kind="contact",
                        reference_id="2",
                        display_name="Ada Lovelace",
                        email="ada@example.test",
                    ),
                ),
            )
        )
        registry = PlatformRegistry()
        registry.register(ModuleManifest(
            id="access",
            name="Access",
            version="1.0.0",
            capability_factories={CAPABILITY_ACCESS_PEOPLE_SEARCH: lambda _context: access},
        ))
        registry.register(ModuleManifest(
            id="addresses",
            name="Addresses",
            version="1.0.0",
            capability_factories={CAPABILITY_ADDRESSES_PEOPLE_SEARCH: lambda _context: addresses},
        ))
        registry.configure_capability_context(ModuleContext(registry=registry, settings=object()))

        session = object()
        principal = object()
        groups = search_visible_people(registry, session, principal, query="  ada  ", limit=200)

        self.assertEqual([group.key for group in groups], ["accounts", "contacts"])
        self.assertEqual([len(group.candidates) for group in groups], [1, 1])
        self.assertEqual(access.calls, [(session, principal, "ada", 100)])
        self.assertEqual(addresses.calls, [(session, principal, "ada", 100)])
        self.assertEqual(people_search_providers(None), ())

    def test_omits_empty_groups_and_ignores_unrelated_capabilities(self) -> None:
        registry = PlatformRegistry()
        registry.register(ModuleManifest(
            id="access",
            name="Access",
            version="1.0.0",
            capability_factories={CAPABILITY_ACCESS_PEOPLE_SEARCH: lambda _context: object()},
        ))
        registry.configure_capability_context(ModuleContext(registry=registry, settings=object()))

        self.assertEqual(search_visible_people(registry, object(), object(), query="ada"), ())

    def test_selection_key_is_stable_and_validated(self) -> None:
        self.assertEqual(
            person_selection_key("Account", "account-1", email=" Ada@Example.Test "),
            "account:account-1:ada@example.test",
        )
        with self.assertRaises(ValueError):
            person_selection_key("", "account-1")


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