"""买曝光 / 余额 / 订单历史。

0.1 期只支持 mock=true（--mock 标志位）。每单：
    - 新增 exposure_orders 一行（paid=1 mock=1）
    - exposure_usage.remaining += count
    - total_purchased += count
    - 全部在同一事务（原子）

定价（0.1 期占位）:
    1 次曝光 = 10 分人民币（¥0.10）
    amount_cents = count * 10
    mock 不真扣，但按真定价保留金额字段，方便未来对比 + 对接真支付
"""

from __future__ import annotations

from dataclasses import dataclass

from .db import get_conn, new_id, now_ts

PRICE_PER_EXPOSURE_CENTS = 10
COUNT_MIN = 1
COUNT_MAX = 10_000


class ExposureError(Exception):
    def __init__(self, code: str, msg: str):
        super().__init__(msg)
        self.code = code


@dataclass
class Order:
    id: str
    user_id: str
    count: int
    amount_cents: int
    mock: bool
    paid: bool
    created_at: int


@dataclass
class Balance:
    remaining: int
    total_purchased: int
    last_consumed_at: int | None


def buy(user_id: str, count: int, mock: bool) -> Order:
    """下单 + 充值。0.1 期 mock 必须为 true。"""
    if not isinstance(count, int) or count < COUNT_MIN or count > COUNT_MAX:
        raise ExposureError(
            "invalid_value", f"count 范围 [{COUNT_MIN}, {COUNT_MAX}]，收到 {count!r}"
        )
    if not mock:
        raise ExposureError(
            "mock_required", "0.1 期只支持 --mock；真实支付在 0.2"
        )

    order_id = new_id()
    amount_cents = count * PRICE_PER_EXPOSURE_CENTS
    now = now_ts()

    with get_conn() as conn:
        # 确保 exposure_usage 行存在（verify 时应已建，但防御一下）
        conn.execute(
            "INSERT OR IGNORE INTO exposure_usage (user_id) VALUES (?)",
            (user_id,),
        )
        conn.execute(
            "INSERT INTO exposure_orders "
            "(id, user_id, count, amount_cents, mock, paid, created_at) "
            "VALUES (?, ?, ?, ?, 1, 1, ?)",
            (order_id, user_id, count, amount_cents, now),
        )
        conn.execute(
            "UPDATE exposure_usage "
            "SET remaining = remaining + ?, total_purchased = total_purchased + ? "
            "WHERE user_id = ?",
            (count, count, user_id),
        )

    return Order(
        id=order_id,
        user_id=user_id,
        count=count,
        amount_cents=amount_cents,
        mock=True,
        paid=True,
        created_at=now,
    )


def get_balance(user_id: str) -> Balance:
    with get_conn() as conn:
        row = conn.execute(
            "SELECT remaining, total_purchased, last_consumed_at "
            "FROM exposure_usage WHERE user_id = ?",
            (user_id,),
        ).fetchone()
    if row is None:
        return Balance(remaining=0, total_purchased=0, last_consumed_at=None)
    return Balance(
        remaining=row["remaining"],
        total_purchased=row["total_purchased"],
        last_consumed_at=row["last_consumed_at"],
    )


def list_orders(user_id: str, limit: int = 50) -> list[Order]:
    if limit < 1 or limit > 100:
        raise ExposureError("invalid_value", "limit 范围 [1, 100]")
    with get_conn() as conn:
        rows = conn.execute(
            "SELECT id, user_id, count, amount_cents, mock, paid, created_at "
            "FROM exposure_orders WHERE user_id = ? "
            "ORDER BY created_at DESC, rowid DESC LIMIT ?",
            (user_id, limit),
        ).fetchall()
    return [
        Order(
            id=r["id"],
            user_id=r["user_id"],
            count=r["count"],
            amount_cents=r["amount_cents"],
            mock=bool(r["mock"]),
            paid=bool(r["paid"]),
            created_at=r["created_at"],
        )
        for r in rows
    ]
