"""比价战绩里程碑 CRUD:进度查询 + 逐档领奖。

进度 = comparison_record 里 status='success' 的条数(crud_compare.count_success)。
第 N 档在"成功次数 >= N"时解锁;每档领一次,写 comparison_milestone_claim 去重(标记已领)。
档位金额来自 rewards.get_record_milestones(运营后台可改)。
⚠️ 当前产品定暂不真发金币(后续整体删除该功能):claim 只写领取记录,不调 grant_coins、
不写 coin_transaction,coin_awarded 恒为 0,余额不变。仿一次性任务 (task.py)。
"""
from __future__ import annotations

from dataclasses import dataclass

from sqlalchemy import select
from sqlalchemy.orm import Session

from app.core import rewards
from app.models.comparison_milestone import ComparisonMilestoneClaim
from app.repositories import comparison as crud_compare
from app.repositories import wallet as crud_wallet


class UnknownMilestoneError(Exception):
    """档位序号越界(不在 1..档位数)。"""


class MilestoneLockedError(Exception):
    """该档还没解锁(成功比价次数不够)。"""


class AlreadyClaimedError(Exception):
    """该档已经领过了。"""


@dataclass
class MilestoneState:
    milestone: int  # 1-based 档位序号
    coin: int
    state: str  # claimed / active / locked


@dataclass
class MilestoneStatus:
    success_count: int  # 累计成功比价次数(解锁进度)
    claimable_count: int  # 当前可领(active)档数
    milestones: list[MilestoneState]


def _claimed_set(db: Session, user_id: int) -> set[int]:
    rows = db.execute(
        select(ComparisonMilestoneClaim.milestone).where(
            ComparisonMilestoneClaim.user_id == user_id
        )
    ).scalars().all()
    return set(rows)


def get_status(db: Session, user_id: int) -> MilestoneStatus:
    """各档领取状态:已领=claimed,已解锁未领=active(可领),未解锁=locked。"""
    success_count = crud_compare.count_success(db, user_id)
    claimed = _claimed_set(db, user_id)
    milestones_def = rewards.get_record_milestones(db)

    milestones: list[MilestoneState] = []
    claimable = 0
    for m in range(1, len(milestones_def) + 1):
        if m in claimed:
            state = "claimed"
        elif success_count >= m:
            state = "active"
            claimable += 1
        else:
            state = "locked"
        milestones.append(
            MilestoneState(milestone=m, coin=milestones_def[m - 1], state=state)
        )

    return MilestoneStatus(
        success_count=success_count,
        claimable_count=claimable,
        milestones=milestones,
    )


def claim(db: Session, user_id: int, milestone: int) -> tuple[int, int]:
    """领取第 milestone 档奖励。返回 (发放金币, 领奖后余额)。

    越界抛 UnknownMilestoneError;未解锁抛 MilestoneLockedError;重复领抛 AlreadyClaimedError。
    """
    if milestone < 1 or milestone > len(rewards.get_record_milestones(db)):
        raise UnknownMilestoneError

    existing = db.execute(
        select(ComparisonMilestoneClaim).where(
            ComparisonMilestoneClaim.user_id == user_id,
            ComparisonMilestoneClaim.milestone == milestone,
        )
    ).scalar_one_or_none()
    if existing is not None:
        raise AlreadyClaimedError

    # 解锁校验:成功比价次数必须 >= 档位序号
    if crud_compare.count_success(db, user_id) < milestone:
        raise MilestoneLockedError

    # ⚠️ 比价战绩里程碑暂不真发金币(产品定,后续整体删除该功能):仍记一条领取(去重/标记已领),
    # 但不调 grant_coins、不写 coin_transaction,余额不变,返回发放 0 金币 + 当前余额。
    db.add(
        ComparisonMilestoneClaim(
            user_id=user_id, milestone=milestone, coin_awarded=0
        )
    )
    acc = crud_wallet.get_or_create_account(db, user_id, commit=False)
    db.commit()
    return 0, acc.coin_balance
