"""Recherche sémantique dans le corpus (pgvector, distance cosinus).
Ne renvoie QUE des extraits sourcés — la brique de « sourcé ou silencieux ».
"""

from dataclasses import dataclass

import asyncpg

from .embeddings import Embeddeur
from .ingestion import _vecteur_sql


@dataclass
class ExtraitTrouve:
    source_type: str
    document_id: str | None
    work_order_id: str | None
    titre: str  # nom de fichier ou référence d'OT
    locator: str
    content: str
    score: float  # similarité cosinus (0..1)


async def chercher(
    cnx: asyncpg.Connection,
    embeddeur: Embeddeur,
    question: str,
    limite: int = 5,
) -> list[ExtraitTrouve]:
    vecteur = _vecteur_sql(embeddeur.encoder([question])[0])
    lignes = await cnx.fetch(
        '''
        SELECT c."sourceType", c."documentId", c."workOrderId", c.locator, c.content,
               1 - (c.embedding <=> $1::vector) AS score,
               COALESCE(d."fileName", wo.reference, '?') AS titre
          FROM "RagChunk" c
          LEFT JOIN "Document" d ON d.id = c."documentId"
          LEFT JOIN "WorkOrder" wo ON wo.id = c."workOrderId"
         WHERE c."documentId" IS NULL OR d."inCorpus" -- l'exclusion D3 s'applique aussi à la lecture
         ORDER BY c.embedding <=> $1::vector
         LIMIT $2
        ''',
        vecteur,
        limite,
    )
    return [
        ExtraitTrouve(
            source_type=ligne["sourceType"],
            document_id=str(ligne["documentId"]) if ligne["documentId"] else None,
            work_order_id=str(ligne["workOrderId"]) if ligne["workOrderId"] else None,
            titre=ligne["titre"],
            locator=ligne["locator"],
            content=ligne["content"],
            score=float(ligne["score"]),
        )
        for ligne in lignes
    ]
