from __future__ import annotations

from typing import Any, Protocol

from app.soat_crosswalk.application.resolution import CupsCodeNotFoundError, CupsSoatResolver
from app.soat_crosswalk.domain.models import CrosswalkResolution


class CupsCandidateRetrieverPort(Protocol):
    def buscar(self, consulta: str, k: int = 5) -> list[Any]: ...


class SearchCupsSoatCandidates:
    """Recupera candidatos CUPS y después aplica el cruce exacto; no delega códigos al LLM."""

    def __init__(self, *, retriever: CupsCandidateRetrieverPort, resolver: CupsSoatResolver) -> None:
        self.retriever = retriever
        self.resolver = resolver

    def execute(self, query: str, *, year: int = 2026, limit: int = 5) -> list[CrosswalkResolution]:
        text = str(query or "").strip()
        if not text:
            return []
        results: list[CrosswalkResolution] = []
        seen: set[str] = set()
        for document in self.retriever.buscar(text, k=max(1, limit)):
            metadata = getattr(document, "metadata", {})
            code = str(metadata.get("codigo") or metadata.get("codigo_cups") or "").strip()
            if code in seen or not code.isdigit() or len(code) != 6:
                continue
            seen.add(code)
            try:
                results.append(self.resolver.resolve(code, year))
            except CupsCodeNotFoundError:
                continue
            if len(results) >= limit:
                break
        return results
