"""消息通知中心:13 种通知类型的静态目录 + Push 文案模板。

对应 PRD《消息通知中心》:§1 类型清单 / §3 字段元素 / §5 Push 文案。
这里只放**静态定义**(分类、版式、标题、操作行、Push 模板),供两处消费:
  - repositories/notification.py       消息中心列表按 type 派生分类/版式/标题/操作行
  - api/v1/push.py                     渲染 13 类 push 标题/文案(厂商推送 + 测试端点)

PRD 文案规范(§5):push 标题 ≤11 字、固定文案不带变量;变量只出现在正文里且尽量前置。
模板变量用 `{name}` 占位,渲染时缺省回退 sample_vars(PRD 示例值),保证 mock 阶段随时可发。
"""
from __future__ import annotations

from dataclasses import dataclass, field

# ---------------------------------------------------------------------------
# 分类(仅作卡片头部的分类标签展示;列表不按分类分组——PRD §1 的分组已确认取消,全表时间倒序)
# ---------------------------------------------------------------------------

CATEGORY_WITHDRAW = "withdraw_assistant"
CATEGORY_SYSTEM = "system"
CATEGORY_FEEDBACK = "feedback"
CATEGORY_REPORT = "report"
CATEGORY_INVITE = "invite"

# key → 中文标签
CATEGORIES: dict[str, str] = {
    CATEGORY_WITHDRAW: "提现助手",
    CATEGORY_SYSTEM: "系统通知",
    CATEGORY_FEEDBACK: "我的反馈",
    CATEGORY_REPORT: "我的爆料",
    CATEGORY_INVITE: "好友邀请",
}


def category_label(key: str) -> str:
    return CATEGORIES[key]


# ---------------------------------------------------------------------------
# 卡片版式(PRD §3「版式」列;前端按此渲染五种卡)
# ---------------------------------------------------------------------------

CARD_DUAL_AMOUNT = "dual_amount"    # 双金额卡(金币数 + 现金数)
CARD_WITHDRAW = "withdraw"          # 提现卡(¥金额)
CARD_PLAIN_TEXT = "plain_text"      # 纯文本卡(无数值)
CARD_COIN_REWARD = "coin_reward"    # 金币奖励卡(金币数 + 单位「金币」)
CARD_FRIEND_CASH = "friend_cash"    # 好友现金卡(¥金额)


@dataclass(frozen=True)
class NotificationType:
    """一种通知类型的静态定义(卡片元数据 + Push 模板)。"""

    key: str                    # 类型 key(接口 type 字段;前端按它决定点击跳转,见 PRD §2)
    category: str               # 分类 key(CATEGORIES 之一)
    card_style: str             # 卡片版式(CARD_* 之一)
    card_title: str             # 卡片标题(PRD §3「标题」列)
    action_text: str | None     # 操作行文案;None = 无操作行(如「提现成功」)
    push_title: str             # push 标题(≤11 字固定文案,PRD §5)
    push_body_template: str     # push 正文模板,`{var}` 为变量
    sample_vars: dict[str, str] = field(default_factory=dict)  # PRD 示例值,渲染缺省回退


# 13 种类型,编号/文案与 PRD §1/§3/§5 一一对应(插入顺序 = PRD 编号顺序)。
TYPES: dict[str, NotificationType] = {
    t.key: t
    for t in [
        # -- 提现助手 -------------------------------------------------------
        NotificationType(
            key="reward_expiring",
            category=CATEGORY_WITHDRAW,
            card_style=CARD_DUAL_AMOUNT,
            card_title="金币现金奖励即将失效",
            action_text="立即激活您的收益",
            push_title="您的奖励即将失效",
            push_body_template="{coins}金币和{cash}元现金{days}天后失效，完成快来激活收益",
            sample_vars={"coins": "86", "cash": "12.80", "days": "3"},
        ),
        NotificationType(
            key="reward_expired",
            category=CATEGORY_WITHDRAW,
            card_style=CARD_DUAL_AMOUNT,
            card_title="金币现金奖励已失效",
            action_text="立即赚取新收益",
            push_title="您的奖励已失效",
            push_body_template="{coins}金币和{cash}元现金已过期，完成一次一键领券或一键比价可赚取新收益",
            sample_vars={"coins": "35", "cash": "0.60"},
        ),
        NotificationType(
            key="withdraw_success",
            category=CATEGORY_WITHDRAW,
            card_style=CARD_WITHDRAW,
            card_title="提现成功",
            action_text=None,  # PRD §3:提现成功卡无操作行,点击也无跳转、仅消红点
            push_title="提现到账提醒",
            push_body_template="¥{amount}已存入您的微信钱包，点击查看到账详情",
            sample_vars={"amount": "0.50"},
        ),
        NotificationType(
            key="withdraw_failed",
            category=CATEGORY_WITHDRAW,
            card_style=CARD_WITHDRAW,
            card_title="提现失败，款项已退回",
            action_text="重新提现",
            push_title="提现失败，款项已退回",
            push_body_template="¥{amount}因{reason}退回现金余额，点击重新提现",
            sample_vars={"amount": "3.50", "reason": "微信零钱未实名"},
        ),
        # -- 系统通知(权限异常 ×4;标题里的功能名按类型写死,见 PRD §1/§3)----
        NotificationType(
            key="perm_accessibility",
            category=CATEGORY_SYSTEM,
            card_style=CARD_PLAIN_TEXT,
            card_title="检测到您的比价功能已失效",
            action_text="去开启",
            push_title="检测到您的比价功能已失效",
            push_body_template="未开启将导致核心功能不可用，请尽快来傻瓜比价开启",
        ),
        NotificationType(
            key="perm_battery",
            category=CATEGORY_SYSTEM,
            card_style=CARD_PLAIN_TEXT,
            card_title="检测到您的比价续航保护已失效",
            action_text="去开启",
            push_title="检测到您的比价续航保护已失效",
            push_body_template="未开启将导致核心功能不可用，请尽快来傻瓜比价开启",
        ),
        NotificationType(
            key="perm_autostart",
            category=CATEGORY_SYSTEM,
            card_style=CARD_PLAIN_TEXT,
            card_title="检测到您的比价启动保护已失效",
            action_text="去开启",
            push_title="检测到您的比价启动保护已失效",
            push_body_template="未开启将导致核心功能不可用，请尽快来傻瓜比价开启",
        ),
        NotificationType(
            key="perm_overlay",
            category=CATEGORY_SYSTEM,
            card_style=CARD_PLAIN_TEXT,
            card_title="检测到您的比价按钮已失效",
            action_text="去开启",
            push_title="检测到您的比价按钮已失效",
            push_body_template="未开启将导致核心功能不可用，请尽快来傻瓜比价开启",
        ),
        # -- 我的反馈 -------------------------------------------------------
        NotificationType(
            key="feedback_reply",
            category=CATEGORY_FEEDBACK,
            card_style=CARD_PLAIN_TEXT,
            card_title="傻瓜比价官方回复了您的反馈",
            action_text="查看详情",
            push_title="您的反馈有回复啦",
            push_body_template="您提的建议我们认真看过了，来看看我们的回复吧～",
        ),
        NotificationType(
            key="feedback_reward",
            category=CATEGORY_FEEDBACK,
            card_style=CARD_COIN_REWARD,
            card_title="反馈奖励",
            action_text="查看反馈详情",
            push_title="反馈奖励已到账",
            push_body_template="谢谢您帮傻瓜比价变得更好，{coins}金币已到账，还有一条给您的留言～",
            sample_vars={"coins": "300"},
        ),
        # -- 我的爆料 -------------------------------------------------------
        NotificationType(
            key="report_approved",
            category=CATEGORY_REPORT,
            card_style=CARD_COIN_REWARD,
            card_title="爆料审核通过",
            action_text="查看爆料详情",
            push_title="爆料审核通过",
            push_body_template="您爆料的「{store}」更低价审核通过，{coins}金币已到账，感谢您的分享",
            sample_vars={"store": "蜀大侠火锅", "coins": "1000"},
        ),
        # -- 好友邀请 -------------------------------------------------------
        NotificationType(
            key="invite_order_reward",
            category=CATEGORY_INVITE,
            card_style=CARD_FRIEND_CASH,
            card_title="好友比价成功，现金已到账",
            action_text="邀请更多好友赚现金",
            push_title="您的邀请奖励已到账",
            push_body_template="您的好友「{nickname}」完成首次下单，{amount}元现金已到账",
            sample_vars={"nickname": "柚子", "amount": "2"},
        ),
        NotificationType(
            key="invite_remind",
            category=CATEGORY_INVITE,
            card_style=CARD_PLAIN_TEXT,
            card_title="你邀请的好友还差一步",
            action_text="去提醒 TA",
            push_title="提醒好友完成比价的奖励",
            push_body_template="您的好友「{nickname}」还没完成比价下单，提醒TA完成，您可得{amount}元现金",
            sample_vars={"nickname": "阿泽", "amount": "2"},
        ),
    ]
}


class UnknownNotificationType(ValueError):
    """type key 不在 13 种类型之内。"""


def get_type(type_key: str) -> NotificationType:
    ntype = TYPES.get(type_key)
    if ntype is None:
        raise UnknownNotificationType(
            f"unknown notification type: {type_key!r} (可选: {', '.join(TYPES)})"
        )
    return ntype


def render_push(type_key: str, variables: dict[str, str] | None = None) -> tuple[str, str]:
    """渲染某类型的 push (标题, 正文)。

    variables 覆盖模板变量;缺的变量回退 sample_vars(PRD 示例值)——保证虚拟数据
    阶段不传变量也能发出完整文案。多余的变量忽略。
    """
    ntype = get_type(type_key)
    merged = {**ntype.sample_vars, **(variables or {})}

    class _Fallback(dict):
        def __missing__(self, key: str) -> str:  # 模板变量既没传也没示例值 → 保留 {key} 原样
            return "{" + key + "}"

    body = ntype.push_body_template.format_map(_Fallback(merged))
    return ntype.push_title, body


def push_variable_names(type_key: str) -> list[str]:
    """列出模板里出现的变量名(给 /push/templates 预览用)。"""
    import string

    ntype = get_type(type_key)
    return [
        fname
        for _, fname, _, _ in string.Formatter().parse(ntype.push_body_template)
        if fname
    ]
