"""Top-level Knowledge Base resources — KnowledgeBaseResource and AsyncKnowledgeBaseResource."""

from __future__ import annotations

import logging

from ..._api.client import AsyncBaseResource, BaseResource
from ..._api.generated.knowbase.knowbase__api__knowbase.client import (
    KnowbaseKnowbaseAPI as _AsyncAPI,
)
from ..._api.generated.knowbase.knowbase__api__knowbase.models import (
    KBSearchResponse,
    SearchRequestRequest,
)
from ..._api.generated.knowbase.knowbase__api__knowbase.sync_client import (
    SyncKnowbaseKnowbaseAPI as _SyncAPI,
)
from ..._config import SDKConfig
from ...exceptions import api_error_handler, async_api_error_handler
from ._documents import _AsyncDocumentsResource, _DocumentsResource
from ._projects import _AsyncProjectsResource, _ProjectsResource
from ._sources import _AsyncSourcesResource, _SourcesResource

logger = logging.getLogger(__name__)


class KnowledgeBaseResource(BaseResource):
    """Knowledge Base tool (sync).

    Manage KB projects, upload documents, configure GitHub sources, and search.

    Usage::

        client = SDKRouter(api_key="sk_live_xxx")

        # Create a project
        project = client.knowbase.projects.create(name="My Docs", slug="my-docs")

        # Upload a document
        doc = client.knowbase.documents("my-docs").upload(
            title="API Guide", content="# API Guide\\n...",
        )

        # Add a GitHub source and trigger crawl
        source = client.knowbase.sources("my-docs").add(url="https://github.com/org/repo")
        client.knowbase.sources("my-docs").crawl(source.id)

        # Search
        results = client.knowbase.search("my-docs", "how to authenticate")
    """

    def __init__(self, config: SDKConfig) -> None:
        super().__init__(config)
        self._api = _SyncAPI(self._http_client)
        self._projects: _ProjectsResource | None = None
        self._documents: dict[str, _DocumentsResource] = {}
        self._sources: dict[str, _SourcesResource] = {}

    @property
    def projects(self) -> _ProjectsResource:
        """CRUD for KB projects."""
        if self._projects is None:
            self._projects = _ProjectsResource(self._config)
        return self._projects

    def documents(self, project_slug: str) -> _DocumentsResource:
        """Documents resource scoped to a project."""
        if project_slug not in self._documents:
            self._documents[project_slug] = _DocumentsResource(self._config, project_slug)
        return self._documents[project_slug]

    def sources(self, project_slug: str) -> _SourcesResource:
        """Data sources resource scoped to a project."""
        if project_slug not in self._sources:
            self._sources[project_slug] = _SourcesResource(self._config, project_slug)
        return self._sources[project_slug]

    @api_error_handler
    def search(
        self,
        project_slug: str,
        query: str,
        *,
        limit: int = 10,
        threshold: float | None = None,
    ) -> KBSearchResponse:
        """Semantic vector search within a knowledge base project.

        Args:
            project_slug: Project identifier slug.
            query: Search query text (any language).
            limit: Max number of results to return (default: 10).
            threshold: Minimum similarity score 0.0–1.0 (uses project default if None).

        Returns:
            KBSearchResponse with ranked results, token count, and timing.
        """
        logger.debug("KB search: project=%s query=%r limit=%d", project_slug, query, limit)
        data = SearchRequestRequest(query=query, limit=limit, threshold=threshold)
        result = self._api.projects_search_create(project_slug=project_slug, data=data)
        logger.info("KB search: project=%s found=%d", project_slug, result.total)
        return result


class AsyncKnowledgeBaseResource(AsyncBaseResource):
    """Knowledge Base tool (async).

    Async equivalent of :class:`KnowledgeBaseResource`.
    """

    def __init__(self, config: SDKConfig) -> None:
        super().__init__(config)
        self._api = _AsyncAPI(self._http_client)
        self._projects: _AsyncProjectsResource | None = None
        self._documents: dict[str, _AsyncDocumentsResource] = {}
        self._sources: dict[str, _AsyncSourcesResource] = {}

    @property
    def projects(self) -> _AsyncProjectsResource:
        """CRUD for KB projects."""
        if self._projects is None:
            self._projects = _AsyncProjectsResource(self._config)
        return self._projects

    def documents(self, project_slug: str) -> _AsyncDocumentsResource:
        """Documents resource scoped to a project."""
        if project_slug not in self._documents:
            self._documents[project_slug] = _AsyncDocumentsResource(self._config, project_slug)
        return self._documents[project_slug]

    def sources(self, project_slug: str) -> _AsyncSourcesResource:
        """Data sources resource scoped to a project."""
        if project_slug not in self._sources:
            self._sources[project_slug] = _AsyncSourcesResource(self._config, project_slug)
        return self._sources[project_slug]

    @async_api_error_handler
    async def search(
        self,
        project_slug: str,
        query: str,
        *,
        limit: int = 10,
        threshold: float | None = None,
    ) -> KBSearchResponse:
        """Semantic vector search within a knowledge base project."""
        logger.debug("KB async search: project=%s query=%r limit=%d", project_slug, query, limit)
        data = SearchRequestRequest(query=query, limit=limit, threshold=threshold)
        result = await self._api.projects_search_create(project_slug=project_slug, data=data)
        logger.info("KB async search: project=%s found=%d", project_slug, result.total)
        return result


__all__ = [
    "KnowledgeBaseResource",
    "AsyncKnowledgeBaseResource",
]
