from __future__ import annotations

import unittest

from govoplan_core.core.modules import ModuleContext, ModuleManifest
from govoplan_core.core.registry import PlatformRegistry
from govoplan_core.core.search import (
    SearchAuthorizationRequest,
    SearchBackfillPage,
    SearchBackfillRequest,
    SearchDocument,
    SearchProvider,
    SearchProviderRegistration,
    SearchQuery,
    SearchResourceReference,
    SearchResourceType,
    SearchResult,
    SearchSourceProvider,
    SearchSourceProviderRegistration,
)


class _Provider:
    def search(self, session, principal, *, query):
        del session, principal
        return (
            SearchResult(
                provider_id="test",
                module_id="test",
                resource_type="record",
                resource_id="1",
                title=query.text,
                url="/test/1",
            ),
        )


class _Source:
    def resource_types(self):
        return (
            SearchResourceType(
                provider_id="test.records",
                module_id="test",
                resource_type="record",
                label="Records",
            ),
        )

    def backfill(self, session, *, request):
        del session
        return SearchBackfillPage(
            documents=(),
            next_cursor=None,
            complete=True,
            high_watermark=request.cursor,
        )

    def authorize(self, session, principal, *, requests):
        del session, principal
        return {
            request.reference.key: True
            for request in requests
        }


class SearchContractTests(unittest.TestCase):
    def test_query_and_restricted_document_are_bounded(self) -> None:
        query = SearchQuery(text=" permit ", tenant_id="tenant-1", limit=20)
        document = SearchDocument(
            tenant_id="tenant-1",
            module_id="cases",
            resource_type="case",
            resource_id="case-1",
            title="Permit",
            url="/cases/case-1",
            acl_tokens=("account:account-1",),
        )

        self.assertEqual("permit", query.text)
        self.assertEqual("restricted", document.visibility)
        with self.assertRaises(ValueError):
            SearchDocument(
                tenant_id="tenant-1",
                module_id="cases",
                resource_type="case",
                resource_id="case-1",
                title="Permit",
                url="/cases/case-1",
            )
        with self.assertRaisesRegex(ValueError, "body"):
            SearchDocument(
                tenant_id="tenant-1",
                module_id="cases",
                resource_type="case",
                resource_id="case-1",
                title="Permit",
                url="/cases/case-1",
                body="x" * 200_001,
                acl_tokens=("account:account-1",),
            )

    def test_manifest_provider_registration_resolves_lazily(self) -> None:
        registry = PlatformRegistry()
        registry.register(
            ModuleManifest(
                id="test",
                name="Test",
                version="1",
                search_providers=(
                    SearchProviderRegistration(
                        id="test.records",
                        factory=lambda context: _Provider(),
                        resource_types=("record",),
                    ),
                ),
                search_sources=(
                    SearchSourceProviderRegistration(
                        id="test.records",
                        factory=lambda context: _Source(),
                    ),
                ),
            )
        )
        registry.configure_capability_context(
            ModuleContext(registry=registry, settings=object())
        )

        providers = registry.search_providers()
        self.assertEqual(1, len(providers))
        self.assertIsInstance(providers[0][1], SearchProvider)
        sources = registry.search_sources()
        self.assertEqual(1, len(sources))
        self.assertIsInstance(sources[0][1], SearchSourceProvider)
        request = SearchAuthorizationRequest(
            reference=SearchResourceReference(
                tenant_id="tenant-1",
                module_id="test",
                resource_type="record",
                resource_id="1",
            ),
            source_revision="1",
        )
        self.assertTrue(
            sources[0][1].authorize(
                object(),
                object(),
                requests=(request,),
            )[request.reference.key]
        )
        page = sources[0][1].backfill(
            object(),
            request=SearchBackfillRequest(
                tenant_id="tenant-1",
                provider_id="test.records",
                resource_type="record",
                rebuild_id="rebuild-1",
            ),
        )
        self.assertTrue(page.complete)


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