from __future__ import annotations

import json
import urllib.request
from typing import Any, Dict, Optional

from .app import build_services
from .models import SearchQuery, search_response


class SemanticIndexClient:
    def __init__(
        self,
        base_url: Optional[str] = None,
        api_key: Optional[str] = None,
        search_service: Optional[Any] = None,
    ) -> None:
        self.base_url = base_url.rstrip("/") if base_url else None
        self.api_key = api_key
        self.search_service = search_service

    @classmethod
    def local(cls) -> "SemanticIndexClient":
        return cls(search_service=build_services()["search"])

    def search(self, query: str, **filters: Any) -> Dict[str, Any]:
        if self.base_url:
            return self._post_json("/search", {"query": query, **filters})
        search_service = self.search_service or build_services()["search"]
        search_query = SearchQuery(
            text=query,
            source=filters.get("source"),
            project_id=filters.get("project_id"),
            project_identifier=filters.get("project_identifier"),
            doc_type=filters.get("doc_type"),
            issue_id=filters.get("issue_id"),
            contact_id=filters.get("contact_id"),
            contact_email=filters.get("contact_email"),
            date_from=filters.get("date_from"),
            date_to=filters.get("date_to"),
            limit=int(filters.get("limit", 10)),
            include_snippets=bool(filters.get("include_snippets", True)),
        )
        return search_response(search_query, search_service.search(search_query))

    def get_document(self, document_id: str) -> Dict[str, Any]:
        if self.base_url:
            return self._get_json(f"/documents/{document_id}")
        search_service = self.search_service or build_services()["search"]
        return search_service.get_document(document_id) or {"error": "not_found", "id": document_id}

    def _post_json(self, path: str, payload: Dict[str, Any]) -> Dict[str, Any]:
        data = json.dumps(payload).encode("utf-8")
        request = urllib.request.Request(
            f"{self.base_url}{path}",
            data=data,
            headers=self._headers(),
            method="POST",
        )
        with urllib.request.urlopen(request, timeout=60) as response:
            return json.loads(response.read().decode("utf-8"))

    def _get_json(self, path: str) -> Dict[str, Any]:
        request = urllib.request.Request(f"{self.base_url}{path}", headers=self._headers())
        with urllib.request.urlopen(request, timeout=60) as response:
            return json.loads(response.read().decode("utf-8"))

    def _headers(self) -> Dict[str, str]:
        headers = {"Content-Type": "application/json"}
        if self.api_key:
            headers["Authorization"] = f"Bearer {self.api_key}"
        return headers
