"""admin「领券数据」看板:发起/完成数 + 领券耗时(均值 + P5/P50/P95/P99)+ 按天趋势 + 逐条明细。

任意已登录 admin 可看(只读)。聚合逻辑在 app/admin/repositories/coupon_data.py。
数据源 coupon_session(客户端 /api/v1/coupon/session 两段上报)。
"""
from __future__ import annotations

from datetime import date as _date
from typing import Annotated

from fastapi import APIRouter, Depends, HTTPException, Query

from app.admin.deps import AdminDb, get_current_admin
from app.admin.repositories import coupon_data
from app.admin.schemas.coupon_data import (
    CouponDataDaily,
    CouponDataHourly,
    CouponDataOut,
    CouponDataRow,
    CouponDataSummary,
    CouponPointDetail,
    CouponPointDetailsOut,
    CouponSlotRow,
    CouponSlotsOut,
    CouponUserRecordsOut,
)
from app.core.rewards import cn_today

router = APIRouter(
    prefix="/admin/api/coupon-data",
    tags=["admin-coupon-data"],
    dependencies=[Depends(get_current_admin)],
)

# 区间最大跨度(天);超出拒绝,避免一次拉过多天拖垮接口(对齐广告收益报表)。
_MAX_RANGE_DAYS = 92


def _parse_day(value: str | None, *, field: str, default: _date) -> _date:
    if value is None:
        return default
    try:
        return _date.fromisoformat(value)
    except ValueError as e:
        raise HTTPException(status_code=422, detail=f"{field} 需为 YYYY-MM-DD") from e


@router.get(
    "",
    response_model=CouponDataOut,
    summary="领券数据看板(发起/完成数 + 耗时分位 + 按天趋势 + 逐条明细)",
)
def get_coupon_data(
    db: AdminDb,
    date_from: Annotated[str | None, Query(description="起始日 北京 YYYY-MM-DD,默认今天")] = None,
    date_to: Annotated[str | None, Query(description="结束日 北京 YYYY-MM-DD,闭区间,默认=date_from")] = None,
    user: Annotated[str | None, Query(description="用户手机号/昵称模糊搜;不传=全部")] = None,
    app_env: Annotated[str, Query(description="prod(默认) / dev / all(全部环境)")] = "prod",
    status: Annotated[
        list[str] | None,
        Query(description="领券状态多选 started/completed/failed/abandoned;不传=全部"),
    ] = None,
    granularity: Annotated[
        str, Query(description="day=按天 / hour=按小时(北京);区间>1 天建议 day")
    ] = "day",
    limit: Annotated[int, Query(ge=1, le=1000, description="每页条数(分页大小)")] = 500,
    offset: Annotated[int, Query(ge=0, description="分页偏移(已跳过条数)=(页码-1)×每页条数")] = 0,
    sort: Annotated[
        str, Query(description="排序:time=发起时间倒序(默认) / elapsed=耗时倒序")
    ] = "time",
) -> CouponDataOut:
    today = cn_today()
    d_from = _parse_day(date_from, field="date_from", default=today)
    d_to = _parse_day(date_to, field="date_to", default=d_from)
    if d_to < d_from:
        raise HTTPException(status_code=422, detail="date_to 不能早于 date_from")
    if (d_to - d_from).days + 1 > _MAX_RANGE_DAYS:
        raise HTTPException(status_code=422, detail=f"区间最长 {_MAX_RANGE_DAYS} 天")

    # 报表默认只看 prod(对齐广告报表防串台口径);app_env=all 时不过滤、看全部环境。
    env = None if app_env == "all" else app_env
    result = coupon_data.coupon_data_report(
        db, date_from=d_from.isoformat(), date_to=d_to.isoformat(),
        user=user, app_env=env, statuses=status, granularity=granularity,
        limit=limit, offset=offset, sort=sort,
    )
    return CouponDataOut(
        date_from=d_from.isoformat(),
        date_to=d_to.isoformat(),
        summary=CouponDataSummary(**result["summary"]),
        daily=[CouponDataDaily(**d) for d in result["daily"]],
        hourly=[CouponDataHourly(**h) for h in result["hourly"]],
        total=result["total"],
        items=[CouponDataRow(**r) for r in result["items"]],
    )


@router.get(
    "/coupons",
    response_model=CouponSlotsOut,
    summary="按券成功率(coupon_id 粒度;成功/(成功+失败),skipped 排除,设备-天口径)",
)
def get_coupon_slots(
    db: AdminDb,
    date_from: Annotated[str | None, Query(description="起始日 北京 YYYY-MM-DD,默认今天")] = None,
    date_to: Annotated[str | None, Query(description="结束日 北京 YYYY-MM-DD,闭区间,默认=date_from")] = None,
    app_env: Annotated[str, Query(description="prod(默认) / dev / all(全部环境)")] = "prod",
) -> CouponSlotsOut:
    today = cn_today()
    d_from = _parse_day(date_from, field="date_from", default=today)
    d_to = _parse_day(date_to, field="date_to", default=d_from)
    if d_to < d_from:
        raise HTTPException(status_code=422, detail="date_to 不能早于 date_from")
    if (d_to - d_from).days + 1 > _MAX_RANGE_DAYS:
        raise HTTPException(status_code=422, detail=f"区间最长 {_MAX_RANGE_DAYS} 天")
    env = None if app_env == "all" else app_env
    result = coupon_data.coupon_slot_report(
        db, date_from=d_from.isoformat(), date_to=d_to.isoformat(), app_env=env
    )
    return CouponSlotsOut(
        date_from=d_from.isoformat(),
        date_to=d_to.isoformat(),
        items=[CouponSlotRow(**r) for r in result["items"]],
    )


@router.get(
    "/point-details",
    response_model=CouponPointDetailsOut,
    summary="按 trace 查询单次领券任务的逐券点位明细",
)
def get_coupon_point_details(
    db: AdminDb,
    trace_id: Annotated[str, Query(min_length=1, max_length=64, description="领券 trace_id")],
) -> CouponPointDetailsOut:
    items = coupon_data.coupon_point_details(db, trace_id=trace_id)
    return CouponPointDetailsOut(
        trace_id=trace_id,
        items=[CouponPointDetail(**item) for item in items],
    )


@router.get(
    "/user-records",
    response_model=CouponUserRecordsOut,
    summary="某用户全部领券记录(点手机号抽屉:领券次数 + 记录列表)",
)
def get_user_coupon_records(
    db: AdminDb,
    user_id: Annotated[int, Query(description="用户 id")],
    limit: Annotated[int, Query(ge=1, le=500, description="最多返回条数")] = 100,
    sort_by: Annotated[str, Query(description="兼容 UserRecordsDrawer 参数;固定按发起时间倒序")] = "created_at",
    sort_order: Annotated[str, Query(description="兼容参数,忽略")] = "desc",
) -> CouponUserRecordsOut:
    result = coupon_data.coupon_user_records(db, user_id=user_id, limit=limit)
    return CouponUserRecordsOut(
        items=[CouponDataRow(**r) for r in result["items"]],
        total=result["total"],
    )
