"""
计费工具模块 — 分辨率映射 + token/费用计算

Token 预估公式（火山官方）：(宽 × 高 × 帧率 × 时长) / 1024
单价：元 / 百万 tokens
"""
from decimal import Decimal, ROUND_HALF_UP

# 分辨率 → 像素映射（来自 Seedance 2.0 API 文档）
RESOLUTION_MAP = {
    # 720p
    ('720p', '16:9'): (1280, 720),
    ('720p', '9:16'): (720, 1280),
    ('720p', '4:3'): (1112, 834),
    ('720p', '1:1'): (960, 960),
    ('720p', '3:4'): (834, 1112),
    ('720p', '21:9'): (1470, 630),
    # 480p
    ('480p', '16:9'): (864, 496),
    ('480p', '9:16'): (496, 864),
    ('480p', '4:3'): (752, 560),
    ('480p', '1:1'): (640, 640),
    ('480p', '3:4'): (560, 752),
    ('480p', '21:9'): (992, 432),
    # 1080p (来自火山 API 文档，Seedance 2.0 & 2.0 fast 列)
    ('1080p', '16:9'): (1920, 1080),
    ('1080p', '9:16'): (1080, 1920),
    ('1080p', '4:3'): (1664, 1248),
    ('1080p', '1:1'): (1440, 1440),
    ('1080p', '3:4'): (1248, 1664),
    ('1080p', '21:9'): (2206, 946),
}

# 默认帧率
DEFAULT_FPS = 24


def get_resolution(aspect_ratio: str, tier: str) -> tuple:
    """根据宽高比和分辨率档位返回 (width, height) 像素值。

    tier 必填，不设默认值 — 避免调用者遗漏时静默降级为 720p（违反计费准确性原则）。
    若 (tier, aspect_ratio) 组合不在 RESOLUTION_MAP（如 adaptive），raise KeyError，
    让上游感知并 fail loud。上游（serializer/前端）负责保证合法组合。
    """
    key = (tier, aspect_ratio)
    if key not in RESOLUTION_MAP:
        raise KeyError(
            f'不支持的分辨率组合: tier={tier!r}, aspect_ratio={aspect_ratio!r}. '
            f'仅支持 480p/720p/1080p × 16:9/9:16/4:3/1:1/3:4/21:9'
        )
    return RESOLUTION_MAP[key]


def estimate_tokens(
    width: int,
    height: int,
    duration: int,
    fps: int = DEFAULT_FPS,
    input_video_duration: float = 0,
) -> int:
    """预估视频生成消耗的 tokens。

    火山官方公式：`(输入视频时长 + 输出视频时长) × 宽 × 高 × 帧率 / 1024`

    ⚠️ 这是预估值，仅用于前端展示和额度冻结。
    真实费用以火山 API 返回的 usage.total_tokens 为准（`_settle_payment` 中按实际值结算）。
    最低 token 用量限制是火山计费端的逻辑，我方不在预估端维护该表（避免与官方脱钩）。

    Args:
        width: 输出视频宽度（像素）
        height: 输出视频高度（像素）
        duration: 输出视频时长（秒）
        fps: 帧率，默认 24
        input_video_duration: 输入参考视频的总时长（秒），默认 0

    Returns:
        token 估算值（整数）
    """
    total_duration = duration + (input_video_duration or 0)
    return round(width * height * fps * total_duration / 1024)


def calculate_cost(tokens: int, base_price, markup_percentage) -> Decimal:
    """计算用户费用（加价后）。

    Args:
        tokens: 消耗的 tokens 数
        base_price: 成本价（元/百万tokens）
        markup_percentage: 加价百分比，如 20 表示 20%
    Returns:
        Decimal: 加价后费用，保留 2 位小数
    """
    base_price = Decimal(str(base_price))
    markup = Decimal(str(markup_percentage))
    team_price = base_price * (1 + markup / 100)
    cost = Decimal(str(tokens)) * team_price / Decimal('1000000')
    return cost.quantize(Decimal('0.01'), rounding=ROUND_HALF_UP)


def calculate_base_cost(tokens: int, base_price) -> Decimal:
    """计算平台成本（不加价）。

    Args:
        tokens: 消耗的 tokens 数
        base_price: 成本价（元/百万tokens）
    Returns:
        Decimal: 成本费用，保留 2 位小数
    """
    base_price = Decimal(str(base_price))
    cost = Decimal(str(tokens)) * base_price / Decimal('1000000')
    return cost.quantize(Decimal('0.01'), rounding=ROUND_HALF_UP)
