"""admin 用户管理 schemas。"""
from __future__ import annotations

from datetime import datetime
from typing import Literal

from pydantic import BaseModel, ConfigDict, Field, field_validator


class AdminUserListItem(BaseModel):
    model_config = ConfigDict(from_attributes=True)

    id: int
    phone: str
    nickname: str | None = None
    register_channel: str
    status: str
    debug_trace_enabled: bool = False
    is_high_risk: bool = False
    high_risk_note: str | None = None
    wechat_openid: str | None = None
    wechat_nickname: str | None = None
    created_at: datetime
    last_login_at: datetime
    # 最近活跃 = max(最近登录, 最近发起比价, 最近发起领券);列表页由 queries._attach_last_active
    # 瞬态挂上。其他复用本 schema 的入口(用户 360 等)没挂该属性 → None(前端显示 '-')。
    last_active_at: datetime | None = None


class AdminUserOverview(BaseModel):
    """用户 360 概览:基础资料 + 钱包余额 + 各项 count(历史明细走各自分页接口)。"""

    model_config = ConfigDict(from_attributes=True)

    user: AdminUserListItem
    coin_balance: int
    cash_balance_cents: int
    invite_cash_balance_cents: int  # 邀请奖励金余额(与 cash_balance_cents 物理隔离)
    total_coin_earned: int
    comparison_total: int
    comparison_success: int
    withdraw_total: int
    withdraw_success_cents: int
    feedback_total: int


class UserRewardStats(BaseModel):
    """提现详情抽屉「用户统计区」:按时间窗口算的提现 + 看广告行为统计。

    窗口由 date_from/date_to 决定(都不传 = 注册至今 = 全量);现金余额除外——它是当前快照。
    各「*_cash_cents」是把该来源累计发放金币折算成可提现现金(分):100 金币 = 1 分(COIN_PER_YUAN=10000)。
    eCPM 单位沿用穿山甲原值「分/千次」。
    """

    withdraw_success_cents: int  # 累计提现(窗口内 success 金额)
    cash_balance_cents: int  # 现金余额(当前快照,不随窗口)
    withdraw_total: int  # 提现总次数(窗口内全部状态)
    traditional_task_cash_cents: int  # 传统任务提现(非广告非人工的金币折现)
    reward_video_count: int  # 累计激励视频数(granted 条数)
    reward_video_avg_ecpm: float  # 平均激励视频 eCPM(分/千次)
    reward_video_cash_cents: int  # 激励视频提现(金币折现)
    feed_count: int  # 累计信息流广告数(granted 份数,unit_count 累加)
    feed_avg_ecpm: float  # 全部 Draw/feed 实际展示的平均 eCPM(分/千次,含未发奖展示)
    feed_cash_cents: int  # 信息流广告提现(金币折现)


class UserCoinRecord(BaseModel):
    """金币发放记录(提现详情底部表)。source 见 source_label;非广告来源 ecpm 为 None。"""

    source: str  # reward_video / signin_boost / feed / signin
    source_label: str  # 激励视频 / 签到膨胀 / 信息流广告 / 签到
    created_at: datetime
    ecpm: str | None = None  # 原始 eCPM(分/千次),非广告为 None
    coin: int  # 发放金币数


def _strip_reason(v: str) -> str:
    # min_length=1 放过纯空白(" "),trim 后再校验非空,避免审计记到空原因
    if not v.strip():
        raise ValueError("操作原因不能为空")
    return v.strip()


class GrantCoinsRequest(BaseModel):
    mode: Literal["delta", "set"] = Field(
        "delta", description="delta=增减(amount 为变动量) / set=设为(amount 为目标值,须≥0)"
    )
    amount: int = Field(
        ...,
        description="delta 模式:金币变动(正=增加,负=扣减,不可为 0);set 模式:目标金币值(须≥0)",
    )
    reason: str = Field(..., min_length=1, max_length=128, description="操作原因(必填,入审计)")

    _v_reason = field_validator("reason")(_strip_reason)


class GrantCashRequest(BaseModel):
    # 目标账户:金币兑换的现金(cash_balance_cents)与邀请奖励金(invite_cash_balance_cents)物理隔离,
    # 各调各的、不可串。默认 coin_cash 兼容旧调用。
    account: Literal["coin_cash", "invite_cash"] = Field(
        "coin_cash", description="目标账户:coin_cash=金币兑现金账户 / invite_cash=邀请奖励金账户"
    )
    mode: Literal["delta", "set"] = Field(
        "delta", description="delta=增减(amount_cents 为变动量) / set=设为(amount_cents 为目标值,须≥0)"
    )
    amount_cents: int = Field(
        ...,
        description="delta 模式:现金变动(分,正=增加,负=扣减,不可为 0);set 模式:目标现金值(分,须≥0)",
    )
    reason: str = Field(..., min_length=1, max_length=128, description="操作原因(必填,入审计)")

    _v_reason = field_validator("reason")(_strip_reason)


class SetUserStatusRequest(BaseModel):
    status: Literal["active", "disabled"] = Field(
        ..., description="active=解封 / disabled=封禁(注销 deleted 不走此接口)"
    )


class SetDebugTraceRequest(BaseModel):
    enabled: bool = Field(..., description="是否给该用户开「复制调试链接」权限")


class SetUserRiskRequest(BaseModel):
    is_high_risk: bool = Field(..., description="是否标记为高风险用户")
    note: str | None = Field(
        None,
        max_length=500,
        description="高风险备注；标记高风险时必填，解除后清空",
    )

    @field_validator("note")
    @classmethod
    def validate_note(cls, value: str | None, info):
        if info.data.get("is_high_risk") and not (value or "").strip():
            raise ValueError("标记高风险时必须填写原因")
        return value.strip() if value and value.strip() else None
