"""Admin 管理操作（给 Claude 通过 `xq admin` CLI 用，不给普通用户）。

权限：env `XIANGQIN_ADMIN_USER_IDS=<id>[,<id>...]` 白名单。session 的
user_id 在列表里才能调 admin_* 函数（API 层已在 app.py 拦）。

覆盖 issue #016 / #017 / #021：
- 封号 / 冻结（users.status）
- 举报审核（reports.review_status）
- 业务指标（stats）

**不覆盖**：
- #020 退款（依赖支付宝 refund API，独立 issue）
- admin 操作的 audit log（当前只写 db 更新，下一阶段加 audit_log 表）
"""

from __future__ import annotations

import os
import sqlite3
from dataclasses import dataclass
from typing import Any

from . import db
from .db import now_ts


class AdminError(Exception):
    def __init__(self, code: str, message: str, http_status: int = 400):
        super().__init__(message)
        self.code = code
        self.http_status = http_status


def _get_conn():
    return sqlite3.connect(db.DEFAULT_DB_PATH)


# ─── 权限 ──────────────────────────────────────────────


def is_admin(user_id: str) -> bool:
    """env `XIANGQIN_ADMIN_USER_IDS` 白名单判定。空 env → 全部非 admin。"""
    raw = os.environ.get("XIANGQIN_ADMIN_USER_IDS", "").strip()
    if not raw:
        return False
    allowlist = {x.strip() for x in raw.split(",") if x.strip()}
    return user_id in allowlist


def require_admin(user_id: str) -> None:
    if not is_admin(user_id):
        raise AdminError("not_admin", "当前 user 不是 admin", http_status=403)


# ─── 用户 status（FEAT-025 ban）────────────────────────


@dataclass(frozen=True)
class UserStatus:
    user_id: str
    status: str  # 'active' | 'frozen' | 'banned'
    status_reason: str | None
    status_updated_at: int | None


def get_user_status(user_id: str) -> UserStatus:
    with _get_conn() as conn:
        row = conn.execute(
            "SELECT id, status, status_reason, status_updated_at FROM users WHERE id=?",
            (user_id,),
        ).fetchone()
    if not row:
        raise AdminError("user_not_found", f"user {user_id} 不存在", http_status=404)
    return UserStatus(
        user_id=row[0],
        status=row[1] or "active",
        status_reason=row[2],
        status_updated_at=row[3],
    )


def ban_user(target_user_id: str, reason: str | None, admin_id: str) -> UserStatus:
    """封号（硬封：不能登录 / 发信 / 查 / 任何 session 操作）。"""
    return _set_status(target_user_id, "banned", reason, admin_id)


def freeze_user(target_user_id: str, reason: str | None, admin_id: str) -> UserStatus:
    """冻结（软封，冷静期）：能登录看消息，不能发新信。未来可加业务层拦截。"""
    return _set_status(target_user_id, "frozen", reason, admin_id)


def unban_user(target_user_id: str, admin_id: str) -> UserStatus:
    """解封（banned / frozen → active）。"""
    return _set_status(target_user_id, "active", None, admin_id)


def _set_status(target_user_id: str, status: str, reason: str | None, admin_id: str) -> UserStatus:
    if status not in ("active", "frozen", "banned"):
        raise AdminError("invalid_status", f"status 必须是 active/frozen/banned，收到 {status}")
    now = now_ts()
    with _get_conn() as conn:
        row = conn.execute("SELECT id FROM users WHERE id=?", (target_user_id,)).fetchone()
        if not row:
            raise AdminError("user_not_found", f"user {target_user_id} 不存在", http_status=404)
        conn.execute(
            "UPDATE users SET status=?, status_reason=?, status_updated_at=? WHERE id=?",
            (status, reason, now, target_user_id),
        )
        # banned 时清掉现有 sessions 让其强制下线
        if status == "banned":
            conn.execute("DELETE FROM sessions WHERE user_id=?", (target_user_id,))
    return UserStatus(
        user_id=target_user_id,
        status=status,
        status_reason=reason,
        status_updated_at=now,
    )


def list_users_by_status(status: str, limit: int = 100) -> list[UserStatus]:
    if status not in ("active", "frozen", "banned"):
        raise AdminError("invalid_status", f"status 非法 {status}")
    with _get_conn() as conn:
        rows = conn.execute(
            "SELECT id, status, status_reason, status_updated_at FROM users "
            "WHERE status=? ORDER BY status_updated_at DESC LIMIT ?",
            (status, limit),
        ).fetchall()
    return [
        UserStatus(user_id=r[0], status=r[1], status_reason=r[2], status_updated_at=r[3])
        for r in rows
    ]


# ─── 举报审核（FEAT-028/029）──────────────────────────


@dataclass(frozen=True)
class ReportRow:
    id: str
    message_id: str
    reporter_id: str
    reported_id: str
    reason: str | None
    created_at: int
    review_status: str
    reviewed_by: str | None
    reviewed_at: int | None


def list_pending_reports(limit: int = 50) -> list[ReportRow]:
    """按时间升序（先报的先审）。"""
    with _get_conn() as conn:
        rows = conn.execute(
            """SELECT id, message_id, reporter_id, reported_id, reason, created_at,
                      review_status, reviewed_by, reviewed_at
               FROM reports
               WHERE review_status='pending'
               ORDER BY created_at ASC
               LIMIT ?""",
            (limit,),
        ).fetchall()
    return [ReportRow(*r) for r in rows]


def pass_report(report_id: str, admin_id: str) -> ReportRow:
    """通过审核（无后续动作，只标处理了）。适用于 "看了一眼不违规" 的情况。"""
    return _review(report_id, "passed", admin_id)


def reject_report(report_id: str, admin_id: str) -> ReportRow:
    """驳回（标 spam 举报，不 ban 被举报者）。"""
    return _review(report_id, "rejected", admin_id)


def confirm_report(
    report_id: str,
    admin_id: str,
    ban_target: bool = False,
    ban_reason: str | None = None,
) -> ReportRow:
    """确认违规。可选 ban_target=True 顺手把 reported_id 封号。"""
    row = _review(report_id, "confirmed", admin_id)
    if ban_target:
        ban_user(row.reported_id, ban_reason or f"违规确认（report={report_id}）", admin_id)
    return row


def _review(report_id: str, new_status: str, admin_id: str) -> ReportRow:
    if new_status not in ("passed", "rejected", "confirmed"):
        raise AdminError("invalid_review_status", f"非法 {new_status}")
    now = now_ts()
    with _get_conn() as conn:
        row = conn.execute(
            """SELECT id, message_id, reporter_id, reported_id, reason, created_at,
                      review_status, reviewed_by, reviewed_at
               FROM reports WHERE id=?""",
            (report_id,),
        ).fetchone()
        if not row:
            raise AdminError("report_not_found", f"report {report_id} 不存在", http_status=404)
        if row[6] != "pending":
            raise AdminError(
                "already_reviewed",
                f"report {report_id} 已审核过（{row[6]}），不能重复审",
            )
        conn.execute(
            "UPDATE reports SET review_status=?, reviewed_by=?, reviewed_at=? WHERE id=?",
            (new_status, admin_id, now, report_id),
        )
    # 返回更新后版本
    updated = list(row)
    updated[6] = new_status
    updated[7] = admin_id
    updated[8] = now
    return ReportRow(*updated)


# ─── 业务指标（stats）─────────────────────────────────


def get_stats() -> dict[str, Any]:
    """聚合关键业务指标。没做时间切片（24h/7d），后续加。"""
    with _get_conn() as conn:
        total_users = conn.execute("SELECT COUNT(*) FROM users").fetchone()[0]
        active_users = conn.execute(
            "SELECT COUNT(*) FROM users WHERE status='active' AND deleted_at IS NULL"
        ).fetchone()[0]
        banned_users = conn.execute("SELECT COUNT(*) FROM users WHERE status='banned'").fetchone()[
            0
        ]
        total_messages = conn.execute(
            "SELECT COUNT(*) FROM messages WHERE delivery_status='delivered'"
        ).fetchone()[0]
        total_orders = conn.execute("SELECT COUNT(*) FROM envelope_orders").fetchone()[0]
        paid_orders = conn.execute(
            "SELECT COUNT(*) FROM envelope_orders WHERE paid=1 AND mock=0"
        ).fetchone()[0]
        paid_amount_cents = conn.execute(
            "SELECT COALESCE(SUM(amount_cents), 0) FROM envelope_orders WHERE paid=1 AND mock=0"
        ).fetchone()[0]
        pending_reports = conn.execute(
            "SELECT COUNT(*) FROM reports WHERE review_status='pending'"
        ).fetchone()[0]
    return {
        "users": {
            "total": total_users,
            "active": active_users,
            "banned": banned_users,
        },
        "messages": {"total_delivered": total_messages},
        "orders": {
            "total": total_orders,
            "paid_real": paid_orders,
            "paid_amount_yuan": round(paid_amount_cents / 100, 2),
        },
        "reports": {"pending": pending_reports},
    }


# ─── 业务拦截（banned 用户不能发信 / 买信封）──────────


def assert_user_active(user_id: str) -> None:
    """mail.send / envelope.buy 等入口调用，banned 用户直接拒。"""
    s = get_user_status(user_id)
    if s.status == "banned":
        raise AdminError(
            "user_banned",
            f"账号已封禁（{s.status_reason or '违规'}）",
            http_status=403,
        )
    if s.status == "frozen":
        raise AdminError(
            "user_frozen",
            f"账号被冻结（{s.status_reason or '冷静期'}）",
            http_status=403,
        )
