"""中控振幅统计 API."""
from __future__ import annotations

from typing import Any, Optional

from fastapi import APIRouter, HTTPException, Query
from fastapi.responses import Response
from pydantic import BaseModel, Field

from amp_stats_store import delete_history, get_history, list_history, save_history
from lib.hub.amp_stats_lib import (
    build_export_csv,
    compute_amp_stats,
    export_filename,
    normalize_move_points,
    normalize_weekend_filter,
    reframe_amp_stats,
    rows_page,
)


class ComputeBody(BaseModel):
    symbol: str = "eth"
    start_hour: int = 16
    period: str = "2m"
    custom_days: Optional[int] = None
    move_points: Optional[float] = None
    weekend_filter: str = "all"
    page: int = 1
    page_size: int = 20


class SaveBody(BaseModel):
    result: dict[str, Any] = Field(default_factory=dict)


class ReframeBody(BaseModel):
    """已有日表上改周末/波动点数(不拉 K 线)."""

    rows_all: list[dict[str, Any]] = Field(default_factory=list)
    symbol: str = "eth"
    start_hour: int = 16
    period: str = "2m"
    sample_days: int = 60
    move_points: Optional[float] = None
    weekend_filter: str = "all"
    price_source: str = ""
    inst_id: str = ""
    page: int = 1
    page_size: int = 20


def create_amp_stats_router() -> APIRouter:
    router = APIRouter(prefix="/api/amp-stats", tags=["amp-stats"])

    @router.get("/meta")
    def api_meta():
        return {
            "ok": True,
            "exchange": "okx",
            "symbols": [
                {"key": "eth", "label": "ETH"},
                {"key": "btc", "label": "BTC"},
            ],
            "end_hour": 16,
            "start_hours": list(range(24)),
            "periods": [
                {"key": "1m", "label": "1个月"},
                {"key": "2m", "label": "2个月"},
                {"key": "3m", "label": "3个月"},
                {"key": "6m", "label": "半年"},
                {"key": "1y", "label": "1年"},
                {"key": "custom", "label": "自定义"},
            ],
            "weekend_filters": [
                {"key": "all", "label": "全部"},
                {"key": "exclude", "label": "排除周末"},
                {"key": "only", "label": "仅周末"},
            ],
            "default_period": "2m",
            "default_weekend_filter": "all",
            "timeframe": "1H",
            "metric_note": "振幅与距离均为点数:振幅=最高-最低=(开→高)+(开→低)",
            "move_points_note": "填波动点数后统计振幅≥该点数的天数占比;日表显示开→高/开→低两边点数与振幅是否达标",
        }

    @router.post("/compute")
    def api_compute(body: ComputeBody):
        try:
            result = compute_amp_stats(
                symbol=body.symbol,
                start_hour=body.start_hour,
                period=body.period,
                custom_days=body.custom_days,
                move_points=body.move_points,
                weekend_filter=body.weekend_filter,
            )
        except ValueError as exc:
            raise HTTPException(status_code=400, detail=str(exc)) from exc
        except Exception as exc:
            raise HTTPException(status_code=502, detail=str(exc)) from exc
        page = rows_page(result.get("rows") or [], page=body.page, page_size=body.page_size)
        return {
            "ok": True,
            "result": result,
            "page": page,
        }

    @router.post("/reframe")
    def api_reframe(body: ReframeBody):
        rows_all = body.rows_all or []
        if not rows_all:
            raise HTTPException(status_code=400, detail="无日表可重算")
        try:
            result = reframe_amp_stats(
                rows_all=rows_all,
                symbol=body.symbol,
                start_hour=body.start_hour,
                period=body.period,
                sample_days=body.sample_days,
                move_points=body.move_points,
                weekend_filter=body.weekend_filter,
                price_source=body.price_source,
                inst_id=body.inst_id,
            )
        except ValueError as exc:
            raise HTTPException(status_code=400, detail=str(exc)) from exc
        page = rows_page(result.get("rows") or [], page=body.page, page_size=body.page_size)
        return {"ok": True, "result": result, "page": page}

    @router.get("/history")
    def api_history(symbol: str = "", limit: int = 50):
        return {"ok": True, "items": list_history(symbol=symbol, limit=limit)}

    @router.post("/history")
    def api_history_save(body: SaveBody):
        payload = body.result if isinstance(body.result, dict) else {}
        if not payload.get("rows") and not payload.get("rows_all") and not payload.get("summary"):
            raise HTTPException(status_code=400, detail="无可保存的结果")
        item = save_history(payload)
        return {"ok": True, "item": item}

    @router.get("/history/{item_id}")
    def api_history_detail(item_id: str):
        item = get_history(item_id)
        if not item:
            raise HTTPException(status_code=404, detail="历史不存在")
        return {"ok": True, "item": item}

    @router.delete("/history/{item_id}")
    def api_history_delete(item_id: str):
        if not delete_history(item_id):
            raise HTTPException(status_code=404, detail="历史不存在")
        return {"ok": True}

    @router.get("/export")
    def api_export(
        history_id: str = Query(default=""),
        symbol: str = Query(default="eth"),
        start_hour: int = Query(default=16),
        period: str = Query(default="2m"),
        custom_days: Optional[int] = Query(default=None),
        move_points: Optional[float] = Query(default=None),
        weekend_filter: str = Query(default="all"),
    ):
        if (history_id or "").strip():
            item = get_history(history_id.strip())
            if not item:
                raise HTTPException(status_code=404, detail="历史不存在")
            rows_all = item.get("rows_all") or item.get("rows") or []
            use_mp = move_points if move_points is not None else item.get("move_points")
            try:
                payload = reframe_amp_stats(
                    rows_all=rows_all,
                    symbol=item.get("symbol") or symbol,
                    start_hour=int(item.get("start_hour") if item.get("start_hour") is not None else start_hour),
                    period=str(item.get("period") or period),
                    sample_days=int(item.get("sample_days_requested") or 60),
                    move_points=use_mp,
                    weekend_filter=weekend_filter or item.get("weekend_filter") or "all",
                    price_source=str(item.get("price_source") or ""),
                    inst_id=str(item.get("inst_id") or ""),
                    missing=item.get("missing_days") or [],
                )
            except ValueError as exc:
                raise HTTPException(status_code=400, detail=str(exc)) from exc
        else:
            try:
                normalize_weekend_filter(weekend_filter)
                normalize_move_points(move_points)
                payload = compute_amp_stats(
                    symbol=symbol,
                    start_hour=start_hour,
                    period=period,
                    custom_days=custom_days,
                    move_points=move_points,
                    weekend_filter=weekend_filter,
                )
            except ValueError as exc:
                raise HTTPException(status_code=400, detail=str(exc)) from exc
            except Exception as exc:
                raise HTTPException(status_code=502, detail=str(exc)) from exc
        csv_text = build_export_csv(payload)
        name = export_filename(payload)
        return Response(
            content=csv_text.encode("utf-8"),
            media_type="text/csv; charset=utf-8",
            headers={"Content-Disposition": f'attachment; filename="{name}"'},
        )

    return router
