"""看广告金币审计 schemas。

只读对账视图:把"看视频"(ad_reward_record)和"信息流"(ad_feed_reward_record)两类发奖记录,
用与正式发奖相同的公式 [app.core.rewards.calculate_ad_reward_coin] 复算一遍 expected_coin,
和实际入账的 actual_coin 对比,核对金币公式是否生效。字段 snake_case、金额按金币整数。
"""
from __future__ import annotations

from datetime import datetime

from pydantic import BaseModel, Field


class AdCoinAuditRow(BaseModel):
    """单条发奖记录的复算明细。"""

    scene: str = Field(..., description="reward_video(看视频) / feed(信息流)")
    record_id: int = Field(..., description="对应记录表主键")
    user_id: int
    created_at: datetime
    status: str = Field(..., description="granted / capped / ecpm_missing")
    ecpm: str | None = Field(None, description="本次采用的 eCPM 原始值(分/千次展示,SDK getEcpm 原值)")
    ecpm_factor: float | None = Field(None, description="因子1(eCPM 档)")
    units: int = Field(..., description="折算份数:看视频恒为 1;信息流 = 满 10 秒的份数")
    lt_index_start: int | None = Field(None, description="本条占用的当日第几份(起)")
    lt_index_end: int | None = Field(None, description="本条占用的当日第几份(止);看视频 = 起")
    lt_factor_start: float | None = Field(None, description="因子2(LT)起值")
    lt_factor_end: float | None = Field(None, description="因子2(LT)止值;看视频 = 起值")
    expected_coin: int = Field(..., description="按公式复算应发金币")
    actual_coin: int = Field(..., description="实际入账金币")
    matched: bool = Field(..., description="复算与实发是否一致(capped/ecpm_missing 校验是否确为 0)")


class AdCoinFormulaOut(BaseModel):
    """当前金币公式参数(给前端展示规则参照)。"""

    description: str = Field(
        "eCPM元 = getEcpm分 ÷ 100;单份金币 = round(eCPM元 ÷ 1000 × 因子1 × 因子2 × coin_per_yuan);"
        "因子1 按 eCPM元 判档(阈值 100/200/400 元)",
        description="公式说明",
    )
    coin_per_yuan: int = Field(..., description="金币:元 汇率")
    ecpm_unit: str = Field("分/千次展示(SDK getEcpm 原值)", description="eCPM 口径")
    feed_unit_seconds: int = Field(..., description="信息流每多少秒折 1 份")
    # [(因子值, 区间下限, 区间上限或 null)]
    ecpm_factor_tiers: list[tuple[float, int, int | None]] = Field(..., description="因子1 档位表")
    lt_factor_tiers: list[tuple[float, int, int | None]] = Field(..., description="因子2 LT 档位表")


class AdCoinAuditOut(BaseModel):
    """审计响应:公式参照 + 全量统计 + 明细。"""

    date: str = Field(..., description="审计日期(北京时间 YYYY-MM-DD)")
    formula: AdCoinFormulaOut
    total: int = Field(..., description="该筛选下复算总条数(全量,不受 limit/only_mismatch 影响)")
    mismatch_count: int = Field(
        ..., description="全量不一致条数(=0 说明公式全部生效;在截断前统计,可信)"
    )
    truncated: bool = Field(
        ..., description="展示集是否被 limit 截断(true=还有未返回的明细,请缩小范围或调大 limit)"
    )
    items: list[AdCoinAuditRow] = Field(..., description="展示明细;only_mismatch=true 时只含 ✗ 行")
