"""
extractor.analytics.citations — Provenance citations for RAG answers.

All logic is deterministic; no external dependencies beyond the entity_index module.
"""

from __future__ import annotations

from dataclasses import dataclass, field

from .entity_index import EntityIndex, EntityMention


@dataclass
class EntityCitation:
    canonical_id: str
    canonical_text: str
    entity_type: str
    surface_form: str  # how it appeared in the source
    source_filename: str
    page: int | None
    section_path: list[str] = field(default_factory=list)
    element_id: str = ""
    chunk_id: str | None = None
    provenance_str: str = ""  # human-readable

    def __post_init__(self) -> None:
        if not self.provenance_str:
            self.provenance_str = _format_provenance(self)


def _format_provenance(c: EntityCitation) -> str:
    """Build a human-readable provenance string."""
    parts = [c.canonical_text]
    loc = c.source_filename
    if c.page is not None:
        loc += f" p.{c.page}"
    if c.section_path:
        loc += f" \u00a7{c.section_path[-1]}"
    parts.append(loc)
    return " \u2014 ".join(parts)


def _mention_to_citation(mention: EntityMention) -> EntityCitation:
    c = EntityCitation(
        canonical_id=mention.canonical_id or "",
        canonical_text=mention.canonical_text or mention.text,
        entity_type=mention.entity_type,
        surface_form=mention.text,
        source_filename=mention.source_filename,
        page=mention.page,
        section_path=list(mention.section_path),
        element_id=mention.element_id,
        chunk_id=mention.chunk_id,
    )
    return c


def cite_entity(
    canonical_id: str,
    index: EntityIndex,
    max_citations: int = 5,
) -> list[EntityCitation]:
    """Return up to max_citations provenance citations for a canonical entity."""
    mentions = index.mentions_for(canonical_id)
    # De-duplicate by (source_filename, page, element_id) — take first occurrence per combo
    seen: set[tuple] = set()
    result: list[EntityCitation] = []
    for mention in mentions:
        key = (mention.source_filename, mention.page, mention.element_id)
        if key in seen:
            continue
        seen.add(key)
        result.append(_mention_to_citation(mention))
        if len(result) >= max_citations:
            break
    return result


def explain_answer_entities(
    chunks: list[dict],
    index: EntityIndex,
    max_per_entity: int = 3,
) -> dict[str, list[EntityCitation]]:
    """
    Given a list of retrieved chunk dicts (from extractor JSONL), return a dict
    mapping canonical_id → citations for every entity in those chunks.

    Filters out:
    - is_pronoun=True entities
    - entities with no canonical_id
    """
    # Collect all entity surface forms + types from chunks
    candidate_ids: dict[str, None] = {}  # ordered set of canonical_ids

    for chunk in chunks:
        entities = chunk.get("entities") or []
        for ent in entities:
            if not isinstance(ent, dict):
                continue
            if ent.get("is_pronoun"):
                continue
            cid = ent.get("canonical_id")
            if not cid:
                # Try to resolve via index
                entity_type = ent.get("entity_type") or ent.get("type") or ""
                surface = ent.get("text") or ""
                if surface and entity_type:
                    cid = index.resolve(surface, entity_type)
            if cid and cid not in candidate_ids:
                candidate_ids[cid] = None

    result: dict[str, list[EntityCitation]] = {}
    for cid in candidate_ids:
        citations = cite_entity(cid, index, max_citations=max_per_entity)
        if citations:
            result[cid] = citations

    return result
