"""Knowledge Base data sources resources (GitHub crawling)."""

from __future__ import annotations

import logging

from ..._api.client import AsyncBaseResource, BaseResource
from ..._api.generated.knowbase.enums import DataSourceSourceType
from ..._api.generated.knowbase.knowbase__api__knowbase.client import (
    KnowbaseKnowbaseAPI as _AsyncAPI,
)
from ..._api.generated.knowbase.knowbase__api__knowbase.models import (
    DataSource,
    DataSourceCreateRequest,
    DataSourceRequest,
    PaginatedDataSourceList,
    PatchedDataSourceRequest,
)
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

logger = logging.getLogger(__name__)


class _SourcesResource(BaseResource):
    """GitHub data sources for a KB project (sync)."""

    def __init__(self, config: SDKConfig, project_slug: str) -> None:
        super().__init__(config)
        self._api = _SyncAPI(self._http_client)
        self._slug = project_slug

    @api_error_handler
    def list(self, *, page: int = 1, page_size: int = 20) -> PaginatedDataSourceList:
        """List data sources for this project."""
        return self._api.projects_sources_list(  # type: ignore[return-value]
            project_slug=self._slug, page=page, page_size=page_size,
        )

    @api_error_handler
    def add(
        self,
        *,
        url: str,
        branch: str = "main",
        path_filter: str | None = None,
        crawl_interval_hours: int = 24,
    ) -> DataSource:
        """Add a GitHub repository as a data source.

        Args:
            url: GitHub repository URL, e.g. ``https://github.com/org/repo``.
            branch: Branch, tag or commit SHA to crawl (default: main).
            path_filter: Optional subdirectory filter, e.g. ``docs/``.
            crawl_interval_hours: How often to re-crawl (default: 24h).
        """
        logger.debug("KB source add: project=%s url=%s", self._slug, url)
        data = DataSourceCreateRequest(
            source_type=DataSourceSourceType.GITHUB_REPO,
            url=url,
            branch=branch,
            path_filter=path_filter,
            crawl_interval_hours=crawl_interval_hours,
        )
        result = self._api.projects_sources_create(project_slug=self._slug, data=data)
        logger.info("KB source added: project=%s", self._slug)
        return result  # type: ignore[return-value]

    @api_error_handler
    def get(self, source_id: str) -> DataSource:
        """Get a source by ID."""
        return self._api.projects_sources_retrieve(id=source_id, project_slug=self._slug)

    @api_error_handler
    def update(
        self,
        source_id: str,
        *,
        branch: str | None = None,
        path_filter: str | None = None,
        crawl_interval_hours: int | None = None,
        is_active: bool | None = None,
    ) -> DataSource:
        """Update a data source."""
        data = PatchedDataSourceRequest(  # type: ignore[call-arg]
            branch=branch,
            path_filter=path_filter,
            crawl_interval_hours=crawl_interval_hours,
            is_active=is_active,
        )
        return self._api.projects_sources_partial_update(
            id=source_id, project_slug=self._slug, data=data,
        )

    @api_error_handler
    def delete(self, source_id: str) -> None:
        """Remove a data source (does not delete already-ingested documents)."""
        logger.info("KB source delete: project=%s id=%s", self._slug, source_id)
        self._api.projects_sources_destroy(id=source_id, project_slug=self._slug)

    @api_error_handler
    def crawl(self, source_id: str) -> None:
        """Trigger an immediate crawl of this data source (background RQ job)."""
        logger.info("KB source crawl: project=%s id=%s", self._slug, source_id)
        source = self.get(source_id)
        crawl_data = DataSourceRequest(
            source_type=source.source_type,
            url=source.url,
            branch=source.branch,
            path_filter=source.path_filter,
            crawl_interval_hours=source.crawl_interval_hours,
            is_active=source.is_active,
        )
        self._api.projects_sources_crawl_create(
            id=source_id, project_slug=self._slug, data=crawl_data,
        )


class _AsyncSourcesResource(AsyncBaseResource):
    """GitHub data sources for a KB project (async)."""

    def __init__(self, config: SDKConfig, project_slug: str) -> None:
        super().__init__(config)
        self._api = _AsyncAPI(self._http_client)
        self._slug = project_slug

    @async_api_error_handler
    async def list(self, *, page: int = 1, page_size: int = 20) -> PaginatedDataSourceList:
        """List data sources for this project."""
        return await self._api.projects_sources_list(  # type: ignore[return-value]
            project_slug=self._slug, page=page, page_size=page_size,
        )

    @async_api_error_handler
    async def add(
        self,
        *,
        url: str,
        branch: str = "main",
        path_filter: str | None = None,
        crawl_interval_hours: int = 24,
    ) -> DataSource:
        """Add a GitHub repository as a data source."""
        data = DataSourceCreateRequest(
            source_type=DataSourceSourceType.GITHUB_REPO,
            url=url,
            branch=branch,
            path_filter=path_filter,
            crawl_interval_hours=crawl_interval_hours,
        )
        return await self._api.projects_sources_create(project_slug=self._slug, data=data)  # type: ignore[return-value]

    @async_api_error_handler
    async def get(self, source_id: str) -> DataSource:
        """Get a source by ID."""
        return await self._api.projects_sources_retrieve(id=source_id, project_slug=self._slug)

    @async_api_error_handler
    async def update(
        self,
        source_id: str,
        *,
        branch: str | None = None,
        path_filter: str | None = None,
        crawl_interval_hours: int | None = None,
        is_active: bool | None = None,
    ) -> DataSource:
        """Update a data source."""
        data = PatchedDataSourceRequest(  # type: ignore[call-arg]
            branch=branch,
            path_filter=path_filter,
            crawl_interval_hours=crawl_interval_hours,
            is_active=is_active,
        )
        return await self._api.projects_sources_partial_update(
            id=source_id, project_slug=self._slug, data=data,
        )

    @async_api_error_handler
    async def delete(self, source_id: str) -> None:
        """Remove a data source."""
        await self._api.projects_sources_destroy(id=source_id, project_slug=self._slug)

    @async_api_error_handler
    async def crawl(self, source_id: str) -> None:
        """Trigger an immediate crawl of this data source (background RQ job)."""
        source = await self.get(source_id)
        crawl_data = DataSourceRequest(
            source_type=source.source_type,
            url=source.url,
            branch=source.branch,
            path_filter=source.path_filter,
            crawl_interval_hours=source.crawl_interval_hours,
            is_active=source.is_active,
        )
        await self._api.projects_sources_crawl_create(
            id=source_id, project_slug=self._slug, data=crawl_data,
        )


__all__ = [
    "_SourcesResource",
    "_AsyncSourcesResource",
]
