from __future__ import annotations

import httpx

from .models import (
    ArchiveBulkCreateResponse,
    ArchiveJobStatus,
    DataSource,
    DataSourceCreateRequest,
    DataSourceRequest,
    Document,
    DocumentFileUploadRequestRequest,
    DocumentUploadRequest,
    KBSearchResponse,
    KnowbaseProjectsChatSettingsPartialUpdateRequest,
    KnowbaseProjectsDocumentsBulkCreateRequest,
    PaginatedDataSourceList,
    PaginatedDocumentList,
    PaginatedProjectList,
    PaginatedPublicDocumentList,
    PaginatedPublicProjectListList,
    PatchedDataSourceRequest,
    PatchedProjectRequest,
    Project,
    ProjectCreate,
    ProjectCreateRequest,
    ProjectRequest,
    PublicDocumentDetail,
    PublicProject,
    PublicSearchRequestRequest,
    PublicSearchResponse,
    SearchRequestRequest,
)


class SyncKnowbaseKnowbaseAPI:
    """Synchronous API endpoints for Knowbase."""

    def __init__(self, client: httpx.Client):
        """Initialize sync sub-client with shared httpx client."""
        self._client = client

    def projects_list(
        self,
        ordering: str | None = None,
        page: int | None = None,
        page_size: int | None = None,
        search: str | None = None,
    ) -> list[PaginatedProjectList]:
        """
        CRUD for KnowledgeBase Projects. list: GET /api/knowbase/projects/
        create: POST /api/knowbase/projects/ retrieve: GET
        /api/knowbase/projects/{slug}/ update: PATCH
        /api/knowbase/projects/{slug}/ destroy: DELETE
        /api/knowbase/projects/{slug}/
        """
        url = "/api/knowbase/projects/"
        _params = {
            k: v for k, v in {
                "ordering": ordering,
                "page": page,
                "page_size": page_size,
                "search": search,
            }.items() if v is not None
        }
        response = self._client.get(url, params=_params)
        if not response.is_success:
            try:
                error_body = response.json()
            except Exception:
                error_body = response.text
            msg = f"{response.status_code}: {error_body}"
            raise httpx.HTTPStatusError(
                msg, request=response.request, response=response
            )
        return PaginatedProjectList.model_validate(response.json())


    def projects_create(self, data: ProjectCreateRequest) -> ProjectCreate:
        """
        CRUD for KnowledgeBase Projects. list: GET /api/knowbase/projects/
        create: POST /api/knowbase/projects/ retrieve: GET
        /api/knowbase/projects/{slug}/ update: PATCH
        /api/knowbase/projects/{slug}/ destroy: DELETE
        /api/knowbase/projects/{slug}/
        """
        url = "/api/knowbase/projects/"
        response = self._client.post(url, json=data.model_dump(mode="json", exclude_unset=True, exclude_none=True))
        if not response.is_success:
            try:
                error_body = response.json()
            except Exception:
                error_body = response.text
            msg = f"{response.status_code}: {error_body}"
            raise httpx.HTTPStatusError(
                msg, request=response.request, response=response
            )
        return ProjectCreate.model_validate(response.json())


    def projects_documents_list(
        self,
        project_slug: str,
        ordering: str | None = None,
        page: int | None = None,
        page_size: int | None = None,
        search: str | None = None,
    ) -> list[PaginatedDocumentList]:
        """
        Document management within a project. list: GET
        /api/knowbase/projects/{slug}/documents/ retrieve: GET
        /api/knowbase/projects/{slug}/documents/{id}/ upload: POST
        /api/knowbase/projects/{slug}/documents/ destroy: DELETE
        /api/knowbase/projects/{slug}/documents/{id}/
        """
        url = f"/api/knowbase/projects/{project_slug}/documents/"
        _params = {
            k: v for k, v in {
                "ordering": ordering,
                "page": page,
                "page_size": page_size,
                "search": search,
            }.items() if v is not None
        }
        response = self._client.get(url, params=_params)
        if not response.is_success:
            try:
                error_body = response.json()
            except Exception:
                error_body = response.text
            msg = f"{response.status_code}: {error_body}"
            raise httpx.HTTPStatusError(
                msg, request=response.request, response=response
            )
        return PaginatedDocumentList.model_validate(response.json())


    def projects_documents_create(
        self,
        project_slug: str,
        data: DocumentUploadRequest,
    ) -> Document:
        """
        Upload a document manually.
        """
        url = f"/api/knowbase/projects/{project_slug}/documents/"
        response = self._client.post(url, json=data.model_dump(mode="json", exclude_unset=True, exclude_none=True))
        if not response.is_success:
            try:
                error_body = response.json()
            except Exception:
                error_body = response.text
            msg = f"{response.status_code}: {error_body}"
            raise httpx.HTTPStatusError(
                msg, request=response.request, response=response
            )
        return Document.model_validate(response.json())


    def projects_documents_retrieve(self, id: str, project_slug: str) -> Document:
        """
        Document management within a project. list: GET
        /api/knowbase/projects/{slug}/documents/ retrieve: GET
        /api/knowbase/projects/{slug}/documents/{id}/ upload: POST
        /api/knowbase/projects/{slug}/documents/ destroy: DELETE
        /api/knowbase/projects/{slug}/documents/{id}/
        """
        url = f"/api/knowbase/projects/{project_slug}/documents/{id}/"
        response = self._client.get(url)
        if not response.is_success:
            try:
                error_body = response.json()
            except Exception:
                error_body = response.text
            msg = f"{response.status_code}: {error_body}"
            raise httpx.HTTPStatusError(
                msg, request=response.request, response=response
            )
        return Document.model_validate(response.json())


    def projects_documents_destroy(self, id: str, project_slug: str) -> None:
        """
        Document management within a project. list: GET
        /api/knowbase/projects/{slug}/documents/ retrieve: GET
        /api/knowbase/projects/{slug}/documents/{id}/ upload: POST
        /api/knowbase/projects/{slug}/documents/ destroy: DELETE
        /api/knowbase/projects/{slug}/documents/{id}/
        """
        url = f"/api/knowbase/projects/{project_slug}/documents/{id}/"
        response = self._client.delete(url)
        if not response.is_success:
            try:
                error_body = response.json()
            except Exception:
                error_body = response.text
            msg = f"{response.status_code}: {error_body}"
            raise httpx.HTTPStatusError(
                msg, request=response.request, response=response
            )
        return None


    def projects_documents_bulk_create(
        self,
        project_slug: str,
        data: KnowbaseProjectsDocumentsBulkCreateRequest,
    ) -> ArchiveBulkCreateResponse:
        """
        Upload ZIP archive for bulk document ingestion

        Upload a ZIP archive containing code/documentation files. Each file is
        converted to Markdown and indexed asynchronously. Supported formats:
        .md, .mdx, .py, .ts, .tsx, .js, .go, .json, .yaml, .rst, .txt and more.
        """
        url = f"/api/knowbase/projects/{project_slug}/documents/bulk/"
        # Build multipart form data
        _files = {}
        _form_data = {}
        if data.archive is not None:
            _files['archive'] = data.archive
        response = self._client.post(url, files=_files if _files else None, data=_form_data if _form_data else None)
        if not response.is_success:
            try:
                error_body = response.json()
            except Exception:
                error_body = response.text
            msg = f"{response.status_code}: {error_body}"
            raise httpx.HTTPStatusError(
                msg, request=response.request, response=response
            )
        return ArchiveBulkCreateResponse.model_validate(response.json())


    def projects_documents_bulk_status_retrieve(
        self,
        job_id: str,
        project_slug: str,
    ) -> ArchiveJobStatus:
        """
        Get archive ingestion job status

        Poll the status of an archive ingestion job. Returns 'queued' →
        'processing' → 'success' | 'error'. When status='success', result
        contains IngestStats.
        """
        url = f"/api/knowbase/projects/{project_slug}/documents/bulk/{job_id}/status/"
        response = self._client.get(url)
        if not response.is_success:
            try:
                error_body = response.json()
            except Exception:
                error_body = response.text
            msg = f"{response.status_code}: {error_body}"
            raise httpx.HTTPStatusError(
                msg, request=response.request, response=response
            )
        return ArchiveJobStatus.model_validate(response.json())


    def projects_documents_upload_create(
        self,
        project_slug: str,
        data: DocumentFileUploadRequestRequest,
    ) -> Document:
        """
        Upload a file as document

        Upload a file (PDF, MD, TXT, HTML, DOCX) to create a new document.
        Content is extracted and queued for processing (chunking + embedding).
        """
        url = f"/api/knowbase/projects/{project_slug}/documents/upload/"
        # Build multipart form data
        _files = {}
        _form_data = {}
        if data.file is not None:
            _files['file'] = data.file
        _raw_data = data.model_dump(mode="json", exclude_unset=True, exclude_none=True)
        if 'title' in _raw_data and _raw_data['title'] is not None:
            _form_data['title'] = _raw_data['title']
        response = self._client.post(url, files=_files if _files else None, data=_form_data if _form_data else None)
        if not response.is_success:
            try:
                error_body = response.json()
            except Exception:
                error_body = response.text
            msg = f"{response.status_code}: {error_body}"
            raise httpx.HTTPStatusError(
                msg, request=response.request, response=response
            )
        return Document.model_validate(response.json())


    def projects_search_create(
        self,
        project_slug: str,
        data: SearchRequestRequest,
    ) -> KBSearchResponse:
        """
        Search knowledge base

        Semantic vector search within a knowledge base project. Public projects
        are accessible without authentication.
        """
        url = f"/api/knowbase/projects/{project_slug}/search/"
        response = self._client.post(url, json=data.model_dump(mode="json", exclude_unset=True, exclude_none=True))
        if not response.is_success:
            try:
                error_body = response.json()
            except Exception:
                error_body = response.text
            msg = f"{response.status_code}: {error_body}"
            raise httpx.HTTPStatusError(
                msg, request=response.request, response=response
            )
        return KBSearchResponse.model_validate(response.json())


    def projects_sources_list(
        self,
        project_slug: str,
        ordering: str | None = None,
        page: int | None = None,
        page_size: int | None = None,
        search: str | None = None,
    ) -> list[PaginatedDataSourceList]:
        """
        Data source management within a project. list: GET
        /api/knowbase/projects/{slug}/sources/ create: POST
        /api/knowbase/projects/{slug}/sources/ update: PATCH
        /api/knowbase/projects/{slug}/sources/{id}/ destroy: DELETE
        /api/knowbase/projects/{slug}/sources/{id}/ crawl: POST
        /api/knowbase/projects/{slug}/sources/{id}/crawl/
        """
        url = f"/api/knowbase/projects/{project_slug}/sources/"
        _params = {
            k: v for k, v in {
                "ordering": ordering,
                "page": page,
                "page_size": page_size,
                "search": search,
            }.items() if v is not None
        }
        response = self._client.get(url, params=_params)
        if not response.is_success:
            try:
                error_body = response.json()
            except Exception:
                error_body = response.text
            msg = f"{response.status_code}: {error_body}"
            raise httpx.HTTPStatusError(
                msg, request=response.request, response=response
            )
        return PaginatedDataSourceList.model_validate(response.json())


    def projects_sources_create(
        self,
        project_slug: str,
        data: DataSourceCreateRequest,
    ) -> DataSource:
        """
        Create a source using DataSourceCreateSerializer for input, return full
        DataSourceSerializer.
        """
        url = f"/api/knowbase/projects/{project_slug}/sources/"
        response = self._client.post(url, json=data.model_dump(mode="json", exclude_unset=True, exclude_none=True))
        if not response.is_success:
            try:
                error_body = response.json()
            except Exception:
                error_body = response.text
            msg = f"{response.status_code}: {error_body}"
            raise httpx.HTTPStatusError(
                msg, request=response.request, response=response
            )
        return DataSource.model_validate(response.json())


    def projects_sources_retrieve(self, id: str, project_slug: str) -> DataSource:
        """
        Data source management within a project. list: GET
        /api/knowbase/projects/{slug}/sources/ create: POST
        /api/knowbase/projects/{slug}/sources/ update: PATCH
        /api/knowbase/projects/{slug}/sources/{id}/ destroy: DELETE
        /api/knowbase/projects/{slug}/sources/{id}/ crawl: POST
        /api/knowbase/projects/{slug}/sources/{id}/crawl/
        """
        url = f"/api/knowbase/projects/{project_slug}/sources/{id}/"
        response = self._client.get(url)
        if not response.is_success:
            try:
                error_body = response.json()
            except Exception:
                error_body = response.text
            msg = f"{response.status_code}: {error_body}"
            raise httpx.HTTPStatusError(
                msg, request=response.request, response=response
            )
        return DataSource.model_validate(response.json())


    def projects_sources_update(
        self,
        id: str,
        project_slug: str,
        data: DataSourceRequest,
    ) -> DataSource:
        """
        Data source management within a project. list: GET
        /api/knowbase/projects/{slug}/sources/ create: POST
        /api/knowbase/projects/{slug}/sources/ update: PATCH
        /api/knowbase/projects/{slug}/sources/{id}/ destroy: DELETE
        /api/knowbase/projects/{slug}/sources/{id}/ crawl: POST
        /api/knowbase/projects/{slug}/sources/{id}/crawl/
        """
        url = f"/api/knowbase/projects/{project_slug}/sources/{id}/"
        response = self._client.put(url, json=data.model_dump(mode="json", exclude_unset=True, exclude_none=True))
        if not response.is_success:
            try:
                error_body = response.json()
            except Exception:
                error_body = response.text
            msg = f"{response.status_code}: {error_body}"
            raise httpx.HTTPStatusError(
                msg, request=response.request, response=response
            )
        return DataSource.model_validate(response.json())


    def projects_sources_partial_update(
        self,
        id: str,
        project_slug: str,
        data: PatchedDataSourceRequest | None = None,
    ) -> DataSource:
        """
        Data source management within a project. list: GET
        /api/knowbase/projects/{slug}/sources/ create: POST
        /api/knowbase/projects/{slug}/sources/ update: PATCH
        /api/knowbase/projects/{slug}/sources/{id}/ destroy: DELETE
        /api/knowbase/projects/{slug}/sources/{id}/ crawl: POST
        /api/knowbase/projects/{slug}/sources/{id}/crawl/
        """
        url = f"/api/knowbase/projects/{project_slug}/sources/{id}/"
        _json = data.model_dump(mode="json", exclude_unset=True, exclude_none=True) if data else None
        response = self._client.patch(url, json=_json)
        if not response.is_success:
            try:
                error_body = response.json()
            except Exception:
                error_body = response.text
            msg = f"{response.status_code}: {error_body}"
            raise httpx.HTTPStatusError(
                msg, request=response.request, response=response
            )
        return DataSource.model_validate(response.json())


    def projects_sources_destroy(self, id: str, project_slug: str) -> None:
        """
        Data source management within a project. list: GET
        /api/knowbase/projects/{slug}/sources/ create: POST
        /api/knowbase/projects/{slug}/sources/ update: PATCH
        /api/knowbase/projects/{slug}/sources/{id}/ destroy: DELETE
        /api/knowbase/projects/{slug}/sources/{id}/ crawl: POST
        /api/knowbase/projects/{slug}/sources/{id}/crawl/
        """
        url = f"/api/knowbase/projects/{project_slug}/sources/{id}/"
        response = self._client.delete(url)
        if not response.is_success:
            try:
                error_body = response.json()
            except Exception:
                error_body = response.text
            msg = f"{response.status_code}: {error_body}"
            raise httpx.HTTPStatusError(
                msg, request=response.request, response=response
            )
        return None


    def projects_sources_crawl_create(self, id: str, project_slug: str) -> None:
        """
        Trigger crawl

        Trigger an immediate crawl of this data source.
        """
        url = f"/api/knowbase/projects/{project_slug}/sources/{id}/crawl/"
        response = self._client.post(url)
        if not response.is_success:
            try:
                error_body = response.json()
            except Exception:
                error_body = response.text
            msg = f"{response.status_code}: {error_body}"
            raise httpx.HTTPStatusError(
                msg, request=response.request, response=response
            )
        return None


    def projects_retrieve(self, slug: str) -> Project:
        """
        CRUD for KnowledgeBase Projects. list: GET /api/knowbase/projects/
        create: POST /api/knowbase/projects/ retrieve: GET
        /api/knowbase/projects/{slug}/ update: PATCH
        /api/knowbase/projects/{slug}/ destroy: DELETE
        /api/knowbase/projects/{slug}/
        """
        url = f"/api/knowbase/projects/{slug}/"
        response = self._client.get(url)
        if not response.is_success:
            try:
                error_body = response.json()
            except Exception:
                error_body = response.text
            msg = f"{response.status_code}: {error_body}"
            raise httpx.HTTPStatusError(
                msg, request=response.request, response=response
            )
        return Project.model_validate(response.json())


    def projects_update(self, slug: str, data: ProjectRequest) -> Project:
        """
        CRUD for KnowledgeBase Projects. list: GET /api/knowbase/projects/
        create: POST /api/knowbase/projects/ retrieve: GET
        /api/knowbase/projects/{slug}/ update: PATCH
        /api/knowbase/projects/{slug}/ destroy: DELETE
        /api/knowbase/projects/{slug}/
        """
        url = f"/api/knowbase/projects/{slug}/"
        response = self._client.put(url, json=data.model_dump(mode="json", exclude_unset=True, exclude_none=True))
        if not response.is_success:
            try:
                error_body = response.json()
            except Exception:
                error_body = response.text
            msg = f"{response.status_code}: {error_body}"
            raise httpx.HTTPStatusError(
                msg, request=response.request, response=response
            )
        return Project.model_validate(response.json())


    def projects_partial_update(
        self,
        slug: str,
        data: PatchedProjectRequest | None = None,
    ) -> Project:
        """
        CRUD for KnowledgeBase Projects. list: GET /api/knowbase/projects/
        create: POST /api/knowbase/projects/ retrieve: GET
        /api/knowbase/projects/{slug}/ update: PATCH
        /api/knowbase/projects/{slug}/ destroy: DELETE
        /api/knowbase/projects/{slug}/
        """
        url = f"/api/knowbase/projects/{slug}/"
        _json = data.model_dump(mode="json", exclude_unset=True, exclude_none=True) if data else None
        response = self._client.patch(url, json=_json)
        if not response.is_success:
            try:
                error_body = response.json()
            except Exception:
                error_body = response.text
            msg = f"{response.status_code}: {error_body}"
            raise httpx.HTTPStatusError(
                msg, request=response.request, response=response
            )
        return Project.model_validate(response.json())


    def projects_destroy(self, slug: str) -> None:
        """
        CRUD for KnowledgeBase Projects. list: GET /api/knowbase/projects/
        create: POST /api/knowbase/projects/ retrieve: GET
        /api/knowbase/projects/{slug}/ update: PATCH
        /api/knowbase/projects/{slug}/ destroy: DELETE
        /api/knowbase/projects/{slug}/
        """
        url = f"/api/knowbase/projects/{slug}/"
        response = self._client.delete(url)
        if not response.is_success:
            try:
                error_body = response.json()
            except Exception:
                error_body = response.text
            msg = f"{response.status_code}: {error_body}"
            raise httpx.HTTPStatusError(
                msg, request=response.request, response=response
            )
        return None


    def projects_chat_settings_retrieve(self, slug: str) -> None:
        """
        Get or update chat settings for a project.
        """
        url = f"/api/knowbase/projects/{slug}/chat-settings/"
        response = self._client.get(url)
        if not response.is_success:
            try:
                error_body = response.json()
            except Exception:
                error_body = response.text
            msg = f"{response.status_code}: {error_body}"
            raise httpx.HTTPStatusError(
                msg, request=response.request, response=response
            )
        return None


    def projects_chat_settings_partial_update(
        self,
        slug: str,
        data: KnowbaseProjectsChatSettingsPartialUpdateRequest | None = None,
    ) -> None:
        """
        Get or update chat settings for a project.
        """
        url = f"/api/knowbase/projects/{slug}/chat-settings/"
        _json = data.model_dump(mode="json", exclude_unset=True, exclude_none=True) if data else None
        response = self._client.patch(url, json=_json)
        if not response.is_success:
            try:
                error_body = response.json()
            except Exception:
                error_body = response.text
            msg = f"{response.status_code}: {error_body}"
            raise httpx.HTTPStatusError(
                msg, request=response.request, response=response
            )
        return None


    def public_projects_list(
        self,
        ordering: str | None = None,
        page: int | None = None,
        page_size: int | None = None,
        search: str | None = None,
    ) -> list[PaginatedPublicProjectListList]:
        """
        GET /api/knowbase/public/projects/ List all public knowledge base
        projects. No auth required.
        """
        url = "/api/knowbase/public/projects/"
        _params = {
            k: v for k, v in {
                "ordering": ordering,
                "page": page,
                "page_size": page_size,
                "search": search,
            }.items() if v is not None
        }
        response = self._client.get(url, params=_params)
        if not response.is_success:
            try:
                error_body = response.json()
            except Exception:
                error_body = response.text
            msg = f"{response.status_code}: {error_body}"
            raise httpx.HTTPStatusError(
                msg, request=response.request, response=response
            )
        return PaginatedPublicProjectListList.model_validate(response.json())


    def public_projects_documents_list(
        self,
        project_slug: str,
        ordering: str | None = None,
        page: int | None = None,
        page_size: int | None = None,
        search: str | None = None,
    ) -> list[PaginatedPublicDocumentList]:
        """
        GET /api/knowbase/public/projects/{slug}/documents/ List documents of a
        public project. No auth required.
        """
        url = f"/api/knowbase/public/projects/{project_slug}/documents/"
        _params = {
            k: v for k, v in {
                "ordering": ordering,
                "page": page,
                "page_size": page_size,
                "search": search,
            }.items() if v is not None
        }
        response = self._client.get(url, params=_params)
        if not response.is_success:
            try:
                error_body = response.json()
            except Exception:
                error_body = response.text
            msg = f"{response.status_code}: {error_body}"
            raise httpx.HTTPStatusError(
                msg, request=response.request, response=response
            )
        return PaginatedPublicDocumentList.model_validate(response.json())


    def public_projects_documents_retrieve(
        self,
        id: str,
        project_slug: str,
    ) -> PublicDocumentDetail:
        """
        GET /api/knowbase/public/projects/{slug}/documents/{id}/ Retrieve a
        single document with content. No auth required.
        """
        url = f"/api/knowbase/public/projects/{project_slug}/documents/{id}/"
        response = self._client.get(url)
        if not response.is_success:
            try:
                error_body = response.json()
            except Exception:
                error_body = response.text
            msg = f"{response.status_code}: {error_body}"
            raise httpx.HTTPStatusError(
                msg, request=response.request, response=response
            )
        return PublicDocumentDetail.model_validate(response.json())


    def public_projects_search_create(
        self,
        project_slug: str,
        data: PublicSearchRequestRequest,
    ) -> PublicSearchResponse:
        """
        Search public knowledge base

        POST /api/knowbase/public/projects/{slug}/search/ Semantic search within
        a public project. No auth required.
        """
        url = f"/api/knowbase/public/projects/{project_slug}/search/"
        response = self._client.post(url, json=data.model_dump(mode="json", exclude_unset=True, exclude_none=True))
        if not response.is_success:
            try:
                error_body = response.json()
            except Exception:
                error_body = response.text
            msg = f"{response.status_code}: {error_body}"
            raise httpx.HTTPStatusError(
                msg, request=response.request, response=response
            )
        return PublicSearchResponse.model_validate(response.json())


    def public_projects_retrieve(self, slug: str) -> PublicProject:
        """
        GET /api/knowbase/public/projects/{slug}/ Retrieve a public project by
        slug. No auth required.
        """
        url = f"/api/knowbase/public/projects/{slug}/"
        response = self._client.get(url)
        if not response.is_success:
            try:
                error_body = response.json()
            except Exception:
                error_body = response.text
            msg = f"{response.status_code}: {error_body}"
            raise httpx.HTTPStatusError(
                msg, request=response.request, response=response
            )
        return PublicProject.model_validate(response.json())


