from __future__ import annotations

import uuid

from app.core.config import settings
from app.models.internal_retrieve import (
    ChunkType,
    CodeSnippet,
    DocExcerpt,
    HydratedHit,
    HydrationSource,
    RelatedCommit,
    RetrieveMetadata,
    RetrieveRequest,
    RetrieveResponse,
    SourceType,
)

_PROCESS_DELTA_RECORD = "emb_chk_sym_internal_service_commitintel_service_go_ProcessDelta"
_PROCESS_DELTA_TEXT = (
    "func (s *Service) ProcessDelta(ctx context.Context, delta GraphDelta) error { ... }"
)


def build_mock_retrieve_response(request: RetrieveRequest) -> RetrieveResponse:
    """Return contract-faithful mock data (contracts §4.2 / §9)."""
    scenario = _resolve_scenario(request.query_text)
    request_id = request.request_id or f"req_{uuid.uuid4().hex[:12]}"
    builders = {
        "default": _default_response,
        "code_lookup": _code_lookup_response,
        "historical": _historical_response,
        "documentation": _documentation_response,
        "pipeline_overview": _pipeline_overview_response,
        "empty": _empty_response,
    }
    builder = builders.get(scenario, _default_response)
    return builder(request_id)


def _resolve_scenario(query_text: str) -> str:
    override = settings.RETRIEVAL_MOCK_SCENARIO.strip().lower()
    if override:
        return override

    normalized = query_text.strip().lower()
    if not normalized:
        return "empty"
    if "redis consumer" in normalized or "refactor" in normalized and "why" in normalized:
        return "historical"
    if "port" in normalized and ("repo sync" in normalized or "use" in normalized):
        return "documentation"
    if "processdelta" in normalized or "where is" in normalized and "defined" in normalized:
        return "code_lookup"
    if "indexing pipeline" in normalized or "pipeline end to end" in normalized:
        return "pipeline_overview"
    if "commit analysis" in normalized or "commit analysis get triggered" in normalized:
        return "code_lookup"
    return "default"


def _base_metadata(request_id: str, **kwargs) -> RetrieveMetadata:
    return RetrieveMetadata(
        request_id=request_id,
        latency_ms=kwargs.get("latency_ms", 320),
        vector_latency_ms=kwargs.get("vector_latency_ms", 85),
        hydrate_latency_ms=kwargs.get("hydrate_latency_ms", 120),
        graph_latency_ms=kwargs.get("graph_latency_ms", 45),
        retrieval_count=kwargs.get("retrieval_count", 20),
        hydrated_count=kwargs.get("hydrated_count", 18),
        skipped_count=kwargs.get("skipped_count", 2),
        graph_nodes_expanded=kwargs.get("graph_nodes_expanded", 3),
        graph_records_added=kwargs.get("graph_records_added", 1),
    )


def _process_delta_hit() -> HydratedHit:
    return HydratedHit(
        record_id=_PROCESS_DELTA_RECORD,
        source_type=SourceType.CODE,
        score=0.89,
        chunk_type=ChunkType.SYMBOL,
        file_path="internal/service/commitintel/service.go",
        symbol_name="ProcessDelta",
        start_line=42,
        end_line=78,
        graph_node_id="sym_internal_service_commitintel_service_go_ProcessDelta",
        text=_PROCESS_DELTA_TEXT,
        hydration_source=HydrationSource.EMBEDDING_RECORD,
    )


def _process_delta_snippet(*, graph_expanded: bool = False, score: float = 0.89) -> CodeSnippet:
    return CodeSnippet(
        record_id=_PROCESS_DELTA_RECORD,
        file_path="internal/service/commitintel/service.go",
        symbol_name="ProcessDelta",
        symbol_type="function",
        language="go",
        start_line=42,
        end_line=78,
        text=_PROCESS_DELTA_TEXT,
        score=score,
        graph_expanded=graph_expanded,
    )


def _commit_intel_doc(*, graph_expanded: bool = True) -> DocExcerpt:
    return DocExcerpt(
        record_id="emb_chk_doc_commit_intel_overview",
        doc_path="docs/architecture/commit-intel.md",
        section_title="Commit Intelligence",
        section_level=2,
        text="Commit analysis is triggered when Code Parser publishes graph.delta.ready events.",
        score=0.756 if graph_expanded else 0.84,
        graph_expanded=graph_expanded,
    )


def _default_response(request_id: str) -> RetrieveResponse:
    hit = _process_delta_hit()
    snippet = _process_delta_snippet()
    return RetrieveResponse(
        embedding_model="text-embedding-3-small",
        embedding_dimension=1536,
        hits=[hit],
        code_snippets=[snippet],
        doc_excerpts=[],
        related_commits=[],
        metadata=_base_metadata(request_id, retrieval_count=1, hydrated_count=1, skipped_count=0),
    )


def _code_lookup_response(request_id: str) -> RetrieveResponse:
    hit = _process_delta_hit()
    snippet = _process_delta_snippet()
    doc = _commit_intel_doc(graph_expanded=True)
    return RetrieveResponse(
        embedding_model="text-embedding-3-small",
        embedding_dimension=1536,
        hits=[hit],
        code_snippets=[snippet],
        doc_excerpts=[doc],
        related_commits=[],
        metadata=_base_metadata(
            request_id,
            retrieval_count=2,
            hydrated_count=2,
            graph_records_added=1,
        ),
    )


def _historical_response(request_id: str) -> RetrieveResponse:
    commit = RelatedCommit(
        record_id="emb_analysis_redis_consumer_refactor",
        commit_sha="a1b2c3d4",
        summary="Refactored Redis stream consumer to use consumer groups and DLQ handling.",
        impacted_symbols=["Consume", "ProcessStream"],
        changed_files=["internal/redis/consumer.go"],
        score=0.82,
    )
    return RetrieveResponse(
        embedding_model="text-embedding-3-small",
        embedding_dimension=1536,
        hits=[],
        code_snippets=[],
        doc_excerpts=[],
        related_commits=[commit],
        metadata=_base_metadata(
            request_id,
            retrieval_count=1,
            hydrated_count=1,
            graph_latency_ms=0,
            graph_nodes_expanded=0,
            graph_records_added=0,
        ),
    )


def _documentation_response(request_id: str) -> RetrieveResponse:
    doc = DocExcerpt(
        record_id="emb_chk_doc_repo_sync_ports",
        doc_path="docs/deployment/repo-sync.md",
        section_title="Ports and Configuration",
        section_level=2,
        text="Repo Sync Service listens on port 6001 by default.",
        score=0.91,
        graph_expanded=False,
    )
    return RetrieveResponse(
        embedding_model="text-embedding-3-small",
        embedding_dimension=1536,
        hits=[],
        code_snippets=[],
        doc_excerpts=[doc],
        related_commits=[],
        metadata=_base_metadata(
            request_id,
            retrieval_count=1,
            hydrated_count=1,
            graph_latency_ms=0,
            graph_nodes_expanded=0,
            graph_records_added=0,
        ),
    )


def _pipeline_overview_response(request_id: str) -> RetrieveResponse:
    code = CodeSnippet(
        record_id="emb_chk_sym_pipeline_orchestrator",
        file_path="internal/pipeline/orchestrator.go",
        symbol_name="RunPipeline",
        symbol_type="function",
        language="go",
        start_line=10,
        end_line=55,
        text="func RunPipeline(ctx context.Context) error { /* indexing stages */ }",
        score=0.87,
        graph_expanded=False,
    )
    doc = DocExcerpt(
        record_id="emb_chk_doc_indexing_overview",
        doc_path="docs/architecture/indexing-pipeline.md",
        section_title="Indexing Pipeline Overview",
        section_level=1,
        text="The indexing pipeline runs repo sync, docs ingestion, code parser, commit intel, and embedding.",
        score=0.85,
        graph_expanded=False,
    )
    return RetrieveResponse(
        embedding_model="text-embedding-3-small",
        embedding_dimension=1536,
        hits=[],
        code_snippets=[code],
        doc_excerpts=[doc],
        related_commits=[],
        metadata=_base_metadata(
            request_id,
            retrieval_count=2,
            hydrated_count=2,
            graph_latency_ms=0,
            graph_nodes_expanded=0,
            graph_records_added=0,
        ),
    )


def _empty_response(request_id: str) -> RetrieveResponse:
    return RetrieveResponse(
        embedding_model="text-embedding-3-small",
        embedding_dimension=1536,
        hits=[],
        code_snippets=[],
        doc_excerpts=[],
        related_commits=[],
        metadata=_base_metadata(
            request_id,
            latency_ms=50,
            vector_latency_ms=40,
            hydrate_latency_ms=0,
            graph_latency_ms=0,
            retrieval_count=0,
            hydrated_count=0,
            skipped_count=0,
            graph_nodes_expanded=0,
            graph_records_added=0,
        ),
    )
