"""Formal query-generation preview API routes."""
from __future__ import annotations

from typing import Any
from uuid import UUID

from fastapi import APIRouter, Depends, HTTPException, Query

from acquisition.queries.builder import QueryBuildOptions, TREES, build_creation_query_batch
from app.dependencies import _env_file, get_acquisition_repository
from app.routes.acquisition import _model_dump
from app.schemas import QuerySchema, TopicTableQueryPreviewRequest
from core.config import Settings
from core.llm import LLMError, chat_json
from query_planning.sources import (
    PatternTopicBuildConfig,
    PatternTopicBuildSource,
    TopicBuildSourceError,
)
from query_planning.topic_table import (
    PROMPT_NAME,
    PROMPT_VERSION,
    ROUTES,
    TopicTableGenerationError,
    generate_topic_table_preview,
    preview_to_dict,
    topic_table_source_preview_to_dict,
    topic_table_prompt,
)

router = APIRouter(prefix="/api/query-generation", tags=["query-generation"])


def _summary(generated: dict[str, Any]) -> dict[str, Any]:
    families = generated.get("families") or []
    return {
        "family_count": len(families),
        "family_keys": [family.get("key") for family in families],
        "query_count": sum(len(family.get("items") or []) for family in families),
        "kept_count": sum(
            1
            for family in families
            for item in family.get("items") or []
            if item.get("keep", True)
        ),
    }


LIGHT_ITEM_METADATA_KEYS = {
    "page_index",
    "page_rank",
    "source_cursor",
    "content_mode",
    "search_provider",
    "detail_provider",
    "acquisition_match_status",
    "matched_unique_key",
    "skip_reason",
    "unsupported_raw_type",
    "video_url_missing",
}


def _light_metadata(metadata: dict[str, Any] | None) -> dict[str, Any]:
    if not isinstance(metadata, dict):
        return {}
    return {key: metadata[key] for key in LIGHT_ITEM_METADATA_KEYS if key in metadata}


def _normalize_light_query_detail(detail: dict[str, Any]) -> dict[str, Any]:
    media_by_item = {media["item_id"]: media for media in detail.get("media_assets") or []}
    classification_by_item = {row["item_id"]: row for row in detail.get("classifications") or []}
    decode_by_item = {row["item_id"]: row for row in detail.get("decode_summaries") or []}
    platforms: dict[str, dict[str, Any]] = {}
    for raw_job in detail.get("jobs") or []:
        job = _model_dump(raw_job)
        platform = job.get("platform")
        if not platform:
            continue
        platforms.setdefault(
            platform,
            {
                "platform": platform,
                "status": job.get("status") or "pending",
                "attempt_count": job.get("attempt_count"),
                "display_limit": job.get("display_limit"),
                "search_limit": job.get("search_limit"),
                "error_message": job.get("error_message"),
                "item_ids": [],
                "item_count": 0,
            },
        )

    items: list[dict[str, Any]] = []
    for row in detail.get("items") or []:
        item = _model_dump(row)
        item_id = item["id"]
        classification = classification_by_item.get(item_id)
        payload = {
            "id": item_id,
            "platform": item.get("platform"),
            "title": item.get("title"),
            "raw_summary": item.get("raw_summary"),
            "status": item.get("status"),
            "content_mode": item.get("content_mode"),
            "metadata": _light_metadata(item.get("metadata")),
            "classification": _model_dump(classification) if classification else None,
            "decode_summary": _model_dump(decode_by_item[item_id]) if item_id in decode_by_item else None,
            "media_assets": [],
        }
        if item_id in media_by_item:
            payload["media_assets"] = [_model_dump(media_by_item[item_id])]
        items.append(payload)
        platform = payload["platform"]
        group = platforms.setdefault(
            platform,
            {"platform": platform, "status": "done", "item_ids": [], "item_count": 0},
        )
        if group.get("status") in {None, "pending"}:
            group["status"] = "done"
        group.setdefault("item_ids", []).append(item_id)
        group["item_count"] = len(group["item_ids"])

    return {
        "query": QuerySchema.model_validate(detail["query"]).model_dump(mode="json"),
        "run": _model_dump(detail["run"]) if detail.get("run") else None,
        "jobs": [_model_dump(job) for job in detail.get("jobs") or []],
        "items": items,
        "platforms": platforms,
    }


@router.get("/preview")
def query_generation_preview(
    per: int = Query(default=0, ge=0, le=10000),
    batch_n: int = Query(default=0, ge=0, le=1000),
) -> dict[str, Any]:
    """Preview the currently active formal query families without writing DB rows."""

    settings = Settings.from_env(_env_file())
    generated = build_creation_query_batch(
        settings,
        tree_path=TREES,
        options=QueryBuildOptions(
            per=per,
            batch_n=batch_n,
            active_family_keys=("f1", "f2"),
        ),
    )
    generated["summary"] = _summary(generated)
    return generated


def _topic_source(env_file: str) -> PatternTopicBuildSource:
    return PatternTopicBuildSource(PatternTopicBuildConfig.from_env(env_file))


def _topic_query_chat(system: str, user: str, *, settings: Settings) -> dict[str, Any]:
    return chat_json(
        system,
        user,
        settings=settings,
        timeout=settings.bailian_timeout_seconds,
        trace_stage="query_planning",
        trace_substage="topic_table_query_generation",
        prompt_name=PROMPT_NAME,
    )


@router.get("/topic-table/prompt")
def topic_table_generation_prompt() -> dict[str, Any]:
    """Return the exact versioned Prompt shown by the topic-table preview UI."""

    return {
        "name": PROMPT_NAME,
        "version": PROMPT_VERSION,
        "routes": [
            {"key": key, "label": value["label"], "default_priority": value["priority"]}
            for key, value in ROUTES.items()
        ],
        "system_prompt": topic_table_prompt(),
        "example_request": {
            "topic_build_id": 1229,
            "topic_id": 1392,
            "max_queries": 18,
        },
    }


@router.post("/topic-table/preview")
def topic_table_query_preview(request: TopicTableQueryPreviewRequest) -> dict[str, Any]:
    """Generate Query preview from one topic table without persisting or searching."""

    env_file = _env_file()
    try:
        source_payload = _topic_source(env_file).fetch(request.topic_build_id)
        settings = Settings.from_env(env_file)
        preview = generate_topic_table_preview(
            source_payload,
            topic_id=request.topic_id,
            max_queries=request.max_queries,
            chat_fn=lambda system, user: _topic_query_chat(
                system,
                user,
                settings=settings,
            ),
        )
        return preview_to_dict(preview)
    except TopicBuildSourceError as exc:
        raise HTTPException(status_code=502, detail=str(exc)) from exc
    except LLMError as exc:
        raise HTTPException(status_code=502, detail=f"Query 生成模型调用失败：{exc}") from exc
    except TopicTableGenerationError as exc:
        raise HTTPException(status_code=422, detail=str(exc)) from exc


@router.post("/topic-table/source-preview")
def topic_table_source_preview(request: TopicTableQueryPreviewRequest) -> dict[str, Any]:
    """Read all topic-table source fields without calling an LLM."""

    try:
        source_payload = _topic_source(_env_file()).fetch(request.topic_build_id)
        return topic_table_source_preview_to_dict(
            source_payload,
            topic_id=request.topic_id,
        )
    except TopicBuildSourceError as exc:
        raise HTTPException(status_code=502, detail=str(exc)) from exc
    except TopicTableGenerationError as exc:
        raise HTTPException(status_code=422, detail=str(exc)) from exc


@router.get("/latest-singleton")
def latest_singleton_overview(repo: Any = Depends(get_acquisition_repository)) -> dict[str, Any]:
    """Return links from the query preview board to the latest real singleton run."""

    getter = getattr(repo, "get_latest_singleton_overview", None)
    if getter is None:
        return {"batch": None, "run": None, "queries": [], "decoded_items": []}
    return getter()


@router.get("/latest/queries/{query_id}")
def latest_query_detail(
    query_id: UUID,
    repo: Any = Depends(get_acquisition_repository),
) -> dict[str, Any]:
    """Return search material for one query in the latest real query board batch."""

    detail_getter = getattr(repo, "get_latest_query_result_list", None)
    if detail_getter is None:
        return {"query": None, "jobs": [], "items": [], "platforms": {}}
    return _normalize_light_query_detail(detail_getter(query_id))
