# backend/app/plugins/advanced_stats/schemas.py
from __future__ import annotations

from datetime import date, datetime
from decimal import Decimal
from typing import Any, Literal

from pydantic import BaseModel, Field, field_validator, model_validator

from app.plugins.advanced_stats.dimensions import DIMENSIONS, GRANULARITIES, SORTABLE
from app.plugins.advanced_stats.timerange import (
    QUICK_RANGES,
    TZ_MAX_MINUTES,
    TZ_MIN_MINUTES,
)

DETAIL_LEVELS = ("none", "order", "item")


class ReportQuery(BaseModel):
    """报表查询参数。所有枚举型参数在此做白名单校验，
    不合法直接 422，永远不会流到 SQL 层。"""

    dimension: str = "summary"
    granularity: str = "month"
    range: str = "month"
    date_start: date | None = None
    date_end: date | None = None
    date_basis: Literal["created", "paid"] = "created"
    tz_offset: int = Field(0, ge=TZ_MIN_MINUTES, le=TZ_MAX_MINUTES)

    statuses: list[str] | None = None       # None = 用维度默认或 PAID_STATUSES
    details: str = "none"

    # ── 筛选 ──
    order_no_from: str | None = None
    order_no_to: str | None = None
    total_min: Decimal | None = None
    total_max: Decimal | None = None
    customer_name: str | None = None
    customer_email: str | None = None
    customer_phone: str | None = None
    member_level_ids: list[int] | None = None
    payment_gateways: list[str] | None = None
    shipping_method_ids: list[int] | None = None
    currencies: list[str] | None = None
    country: str | None = None
    province: str | None = None
    city: str | None = None
    district: str | None = None
    postcode: str | None = None
    product_keyword: str | None = None      # 名称或 SKU
    product_ids: list[int] | None = None
    category_ids: list[int] | None = None
    brand_ids: list[int] | None = None
    discount_ids: list[int] | None = None

    # ── 输出控制 ──
    sort: str = "dim_key"
    order: Literal["asc", "desc"] = "desc"
    page: int = Field(1, ge=1)
    page_size: int = Field(50, ge=5, le=1000)

    @field_validator("dimension")
    @classmethod
    def _check_dimension(cls, v: str) -> str:
        if v not in DIMENSIONS:
            raise ValueError(f"未知维度: {v!r}")
        return v

    @field_validator("granularity")
    @classmethod
    def _check_granularity(cls, v: str) -> str:
        if v not in GRANULARITIES:
            raise ValueError(f"未知时间粒度: {v!r}")
        return v

    @field_validator("range")
    @classmethod
    def _check_range(cls, v: str) -> str:
        if v not in QUICK_RANGES:
            raise ValueError(f"未知时间范围: {v!r}")
        return v

    @field_validator("details")
    @classmethod
    def _check_details(cls, v: str) -> str:
        if v not in DETAIL_LEVELS:
            raise ValueError(f"未知明细档位: {v!r}")
        return v

    @field_validator("sort")
    @classmethod
    def _check_sort(cls, v: str) -> str:
        if v not in SORTABLE:
            raise ValueError(f"不可排序字段: {v!r}")
        return v

    @model_validator(mode="after")
    def _check_dates(self):
        if self.range == "custom" and (self.date_start is None or self.date_end is None):
            raise ValueError("range=custom 时必须同时提供 date_start 和 date_end")
        if self.date_start and self.date_end and self.date_start > self.date_end:
            raise ValueError("date_start 不能晚于 date_end")
        return self


class ReportRow(BaseModel):
    dim_key: str                    # 分组键的字符串形式
    dim_label: str                  # 展示名；无 i18n key 时前端直接显示它
    dim_label_key: str | None = None  # i18n key；非空时前端用 $t() 翻译它
    metrics: dict[str, Any]         # 指标名 → 值


class ReportResponse(BaseModel):
    dimension: str
    granularity: str
    date_start: date | None
    date_end: date
    tz_offset: int
    statuses: list[str]
    metric_keys: list[str]          # 本次输出哪些指标列，前端据此渲染表头
    rows: list[ReportRow]
    totals: dict[str, Any]          # 全量合计（不是当前页合计）
    total_rows: int
    page: int
    page_size: int
    notes: list[str] = []           # 口径提示，如"不含 POS 单"


class PresetIn(BaseModel):
    title: str = Field(min_length=1, max_length=100)
    query: dict[str, Any]


class PresetOut(BaseModel):
    id: int
    title: str
    query: dict[str, Any]
    created_at: datetime

    model_config = {"from_attributes": True}
