"""看激励视频冷却策略 —— 与发奖记录查询解耦的纯计算。

当前策略:**每 N 次一轮,看满一轮后强制冷却若干秒**(N / 秒数 取自 [rewards] 常量)。
[repositories.ad_reward.today_status] 只负责取数据(今日 granted 的 created_at 列表),
把"本轮已看几次 + 冷却到几点"的策略判断委托到这里。

⚠️ 这是临时策略,后续要调。换策略(间隔式 / 每日配额式 / 指数退避 …)**只改本文件**,
repository 不碰——这就是把它独立出来的目的。保持 [compute_cooldown] 签名稳定即可。
"""
from __future__ import annotations

from dataclasses import dataclass
from datetime import datetime, timedelta, timezone

from app.core.rewards import VIDEO_ROUND_COOLDOWN_SECONDS, VIDEO_ROUND_REQUIRED_COUNT


@dataclass(frozen=True)
class CooldownState:
    """冷却策略的输出。"""

    round_count: int  # 本轮已看次数 0..N-1(展示用)
    cooldown_until: datetime | None  # 本轮冷却结束时间(UTC);None = 不在冷却


def compute_cooldown(
    granted_times_desc: list[datetime],
    now: datetime,
    *,
    round_size: int = VIDEO_ROUND_REQUIRED_COUNT,
    cooldown_seconds: int = VIDEO_ROUND_COOLDOWN_SECONDS,
) -> CooldownState:
    """按"每 round_size 次一轮、看满一轮后冷却 cooldown_seconds 秒"算本轮进度 + 冷却结束时间。

    :param granted_times_desc: 今日 status=granted 记录的 created_at,**按时间倒序**(最新在前)。
    :param now: 当前时间(UTC,带 tzinfo),用于判断冷却是否已过。
    :param round_size / cooldown_seconds: 策略参数,默认取 rewards 常量,可注入便于测试/调参。

    纯函数,不碰 DB。冷却派生算法:把今日 granted 倒序,跳过当前未完成轮的 round_count 条,
    下一条即"上一轮最后一次"的时间,+ cooldown_seconds 仍 > now 则在冷却中。
    SQLite 上 created_at 可能是 naive,按 UTC 解读再比较。
    """
    used = len(granted_times_desc)
    round_count = used % round_size
    cooldown_until: datetime | None = None
    if used >= round_size:
        # round_count 必 < round_size <= used,索引合法
        last_round_end = granted_times_desc[round_count]
        if last_round_end.tzinfo is None:
            last_round_end = last_round_end.replace(tzinfo=timezone.utc)
        cd_end = last_round_end + timedelta(seconds=cooldown_seconds)
        if cd_end > now:
            cooldown_until = cd_end
    return CooldownState(round_count=round_count, cooldown_until=cooldown_until)
