from __future__ import annotations

from dataclasses import dataclass, field

from rights_filter.analysis.llm_assistance import InternalLlmAssistant
from rights_filter.analysis.risk_scoring import RiskScorer
from rights_filter.analysis.search_query_generation import SearchQueryGenerator
from rights_filter.analysis.search_result_promoter import SearchResultPromoter
from rights_filter.domain.records import (
    Evidence,
    EvidenceSource,
    InMemoryRightsFilterRepository,
)
from rights_filter.integrations.naver_search import NaverSearchAdapter
from rights_filter.integrations.search_policy import SearchApiPolicy


@dataclass
class EnrichmentSummary:
    generated_queries: int = 0
    executed_searches: int = 0
    skipped_searches: int = 0
    provider_failures: int = 0
    summary_failures: int = 0
    failed: int = 0
    failure_reasons: list[str] = field(default_factory=list)


class EvidenceEnricher:
    def __init__(
        self,
        query_generator: SearchQueryGenerator,
        naver_adapter: NaverSearchAdapter,
        search_policy: SearchApiPolicy,
        promoter: SearchResultPromoter,
        llm_assistant: InternalLlmAssistant,
        scorer: RiskScorer,
    ) -> None:
        self.query_generator = query_generator
        self.naver_adapter = naver_adapter
        self.search_policy = search_policy
        self.promoter = promoter
        self.llm_assistant = llm_assistant
        self.scorer = scorer

    def enrich_latest(
        self, repository: InMemoryRightsFilterRepository, submission_id: str
    ) -> EnrichmentSummary:
        runs = repository.analysis_runs_for_submission(submission_id)
        if not runs:
            return EnrichmentSummary(
                failed=1,
                failure_reasons=[f"missing analysis run for {submission_id}"],
            )

        run = runs[-1]
        summary = EnrichmentSummary()
        queries = self.query_generator.generate(
            run.evidence, repository.active_knowledge_entries()
        )
        summary.generated_queries = len(queries)

        new_evidence: list[Evidence] = []
        existing_signatures = _existing_query_signatures(run.evidence)
        for query in queries:
            signature = "naver:" + " ".join(query.lower().split())
            if signature in existing_signatures:
                continue
            found = self.naver_adapter.search(submission_id, query, self.search_policy)
            promoted = self.promoter.promote(found)
            new_evidence.extend(promoted)
            # Each naver_adapter.search() result is homogeneous in source, so
            # classify the single search CALL by its outcome instead of summing
            # per result item (which inflated executed_searches by item count).
            outcome_sources = {item.source for item in promoted}
            if EvidenceSource.SEARCH_SKIPPED in outcome_sources:
                summary.skipped_searches += 1
            elif EvidenceSource.ENRICHMENT_FAILURE in outcome_sources:
                summary.provider_failures += 1
            elif EvidenceSource.NAVER_SEARCH in outcome_sources:
                summary.executed_searches += 1

        source_evidence = [
            item
            for item in [*run.evidence, *new_evidence]
            if item.source
            in {
                EvidenceSource.NAVER_SEARCH,
                EvidenceSource.WEB_DETECTION,
                EvidenceSource.FINGERPRINT,
            }
        ]
        # Only invoke the LLM when no summary exists yet. Previously summarize()
        # ran on every rerun and its result was discarded (and its failure
        # counted) when a summary was already present.
        if not _has_existing_llm_summary(run.evidence):
            llm_summary = self.llm_assistant.summarize(submission_id, source_evidence)
            if llm_summary.source == EvidenceSource.ENRICHMENT_FAILURE:
                summary.summary_failures += 1
            new_evidence.append(llm_summary)

        for item in new_evidence:
            run.add_evidence(item)
        run.score = self.scorer.score(run.evidence)
        return summary


def _existing_query_signatures(evidence: list[Evidence]) -> set[str]:
    return {
        str(item.data["query_signature"])
        for item in evidence
        if item.source
        in {
            EvidenceSource.NAVER_SEARCH,
            EvidenceSource.SEARCH_SKIPPED,
            EvidenceSource.ENRICHMENT_FAILURE,
        }
        and item.data.get("query_signature")
    }


def _has_existing_llm_summary(evidence: list[Evidence]) -> bool:
    return any(item.source == EvidenceSource.LLM_SUMMARY for item in evidence)
