from __future__ import annotations

import httpx

from app.core.config import settings
from app.core.logger import logger
from app.models.enums import LucosSourceType, to_embedding_source_type


class EmbeddingEngineClient:
    def __init__(self) -> None:
        self._base_url = settings.EMBEDDING_ENGINE_URL.rstrip("/")
        self._timeout = settings.EMBEDDING_ENGINE_TIMEOUT_SEC

    def _headers(self) -> dict[str, str]:
        headers = {"Content-Type": "application/json"}
        secret = settings.GATEWAY_INTERNAL_SERVICE_SECRET.strip()
        if secret:
            headers["X-Internal-Secret"] = secret
        return headers

    async def embed_lucos_chunks(self, chunks: list[dict]) -> dict:
        if not chunks:
            return {"requested": 0, "embedded": 0, "indexed": 0, "failed": 0}

        url = f"{self._base_url}/internal/lucos/chunks/embed"
        async with httpx.AsyncClient(timeout=self._timeout) as client:
            response = await client.post(
                url,
                json={"chunks": chunks},
                headers=self._headers(),
            )
            response.raise_for_status()
            return response.json()

    async def delete_chunk_vectors(self, record_ids: list[str]) -> dict:
        if not record_ids:
            return {"deleted": 0, "mongo_updated": 0}

        url = f"{self._base_url}/internal/lucos/chunks/delete"
        async with httpx.AsyncClient(timeout=self._timeout) as client:
            response = await client.post(
                url,
                json={"record_ids": record_ids},
                headers=self._headers(),
            )
            response.raise_for_status()
            return response.json()

    async def retrieve(
        self,
        *,
        repo_id: str,
        snapshot_id: str,
        query_text: str,
        top_k: int,
        request_id: str,
    ) -> dict:
        url = f"{self._base_url}/internal/retrieve"
        payload = {
            "repo_id": repo_id,
            "snapshot_id": snapshot_id,
            "query_text": query_text,
            "top_k": top_k,
            "request_id": request_id,
            "graph_expand": False,
            "filters": {
                "source_types": ["code", "docs"],
            },
        }
        async with httpx.AsyncClient(timeout=self._timeout) as client:
            response = await client.post(url, json=payload)
            response.raise_for_status()
            return response.json()


def build_embedding_record_id(repo_id: str, chunk_id: str) -> str:
    return f"lucos:{repo_id}:{chunk_id}"


def parse_chunk_id_from_record_id(repo_id: str, record_id: str) -> str | None:
    prefix = f"lucos:{repo_id}:"
    if not record_id.startswith(prefix):
        return None
    chunk_id = record_id[len(prefix) :]
    return chunk_id or None


def chunk_to_embed_payload(
    *,
    repo_id: str,
    snapshot_id: str,
    commit_sha: str | None,
    chunk_id: str,
    chunk_hash: str,
    file_path: str,
    content: str,
    source_type: LucosSourceType,
    start_line: int,
    end_line: int,
    language: str | None,
    symbol_name: str | None,
) -> dict:
    return {
        "chunk_id": chunk_id,
        "chunk_hash": chunk_hash,
        "repo_id": repo_id,
        "file_path": file_path,
        "content": content,
        "source_type": to_embedding_source_type(source_type).value,
        "start_line": start_line,
        "end_line": end_line,
        "language": language,
        "symbol_name": symbol_name,
        "snapshot_id": snapshot_id,
        "commit_sha": commit_sha,
    }


async def queue_chunk_embeddings(chunks: list[dict]) -> dict:
    client = EmbeddingEngineClient()
    try:
        return await client.embed_lucos_chunks(chunks)
    except httpx.HTTPError as exc:
        logger.error("Embedding engine request failed: {error}", error=str(exc))
        raise
