"""费用审核智能体 API — 管理会计OS
费用规则配置 + 报销单自动校验 + 人工审批流程 + 审核看板统计

流程:
1. 提交报销单 → 自动校验费用规则
2. 超限 → 自动打回(returned, 标注原因)
3. 合规 → 待人工审批(pending)
4. 审批通过(approved) / 拒绝(rejected)
"""
import json
import random
from datetime import datetime, date

from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.orm import Session
from sqlalchemy import func

from app.database import get_db
from app.deps import get_entity_id
from app.auth_middleware import require_auth, require_role
from app.models import ExpenseRule, ExpenseReimbursement, OperationLog

router = APIRouter(prefix="/api/cma/expenses", tags=["费用审核"])

# 费用类型中文映射
EXPENSE_TYPE_LABELS = {
    "entertainment": "招待费",
    "travel": "差旅费",
    "office": "办公费",
    "management": "管理费",
}

# 预置规则
PRESET_RULES = [
    {"rule_name": "招待费单笔限额", "dimension": "expense_type", "dimension_value": "",
     "expense_type": "entertainment", "limit_type": "single", "limit_amount": 2000.0,
     "cycle": "single", "remark": "招待费标准：单笔≤2000元"},
    {"rule_name": "招待费部门月限额", "dimension": "department", "dimension_value": "",
     "expense_type": "entertainment", "limit_type": "monthly", "limit_amount": 50000.0,
     "cycle": "monthly", "remark": "招待费标准：部门月限额5万元"},
    {"rule_name": "招待费月度总额限额", "dimension": "expense_type", "dimension_value": "",
     "expense_type": "entertainment", "limit_type": "monthly", "limit_amount": 150000.0,
     "cycle": "monthly", "remark": "公司招待费预算15万/月"},
    {"rule_name": "差旅住宿单晚限额", "dimension": "expense_type", "dimension_value": "",
     "expense_type": "travel", "limit_type": "single", "limit_amount": 300.0,
     "cycle": "single", "remark": "差旅费标准：住宿≤300元/晚"},
    {"rule_name": "差旅交通等级限额", "dimension": "expense_type", "dimension_value": "",
     "expense_type": "travel", "limit_type": "single", "limit_amount": 1500.0,
     "cycle": "single", "remark": "差旅费标准：交通等级（高铁二等座/经济舱）"},
    {"rule_name": "办公费单笔限额", "dimension": "expense_type", "dimension_value": "",
     "expense_type": "office", "limit_type": "single", "limit_amount": 500.0,
     "cycle": "single", "remark": "办公费标准：单笔≤500元"},
    {"rule_name": "管理费月度总额限额", "dimension": "expense_type", "dimension_value": "",
     "expense_type": "management", "limit_type": "monthly", "limit_amount": 910000.0,
     "cycle": "monthly", "remark": "管理费预算91万/月"},
]


def _rule_to_dict(r: ExpenseRule) -> dict:
    return {
        "id": r.id,
        "rule_name": r.rule_name,
        "dimension": r.dimension,
        "dimension_value": r.dimension_value,
        "expense_type": r.expense_type,
        "expense_type_label": EXPENSE_TYPE_LABELS.get(r.expense_type, r.expense_type),
        "limit_type": r.limit_type,
        "limit_amount": r.limit_amount,
        "cycle": r.cycle,
        "status": r.status,
        "remark": r.remark,
        "created_at": r.created_at.isoformat() if r.created_at else None,
    }


def _reimb_to_dict(r: ExpenseReimbursement) -> dict:
    return {
        "id": r.id,
        "reimb_no": r.reimb_no,
        "applicant": r.applicant,
        "department": r.department,
        "expense_type": r.expense_type,
        "expense_type_label": EXPENSE_TYPE_LABELS.get(r.expense_type, r.expense_type),
        "title": r.title,
        "amount": r.amount,
        "expense_date": r.expense_date.isoformat() if r.expense_date else None,
        "attachment": r.attachment,
        "status": r.status,
        "check_result": r.check_result,
        "check_reason": r.check_reason,
        "check_detail": r.check_detail,
        "checked_at": r.checked_at.isoformat() if r.checked_at else None,
        "approver": r.approver,
        "approve_comment": r.approve_comment,
        "approved_at": r.approved_at.isoformat() if r.approved_at else None,
        "created_by": r.created_by,
        "created_at": r.created_at.isoformat() if r.created_at else None,
    }


def _gen_reimb_no(db: Session) -> str:
    """生成报销单号: BX + 年月日 + 序号"""
    today = datetime.now()
    prefix = "BX" + today.strftime("%Y%m%d")
    last = (
        db.query(ExpenseReimbursement)
        .filter(ExpenseReimbursement.reimb_no.like(prefix + "%"))
        .order_by(ExpenseReimbursement.id.desc())
        .first()
    )
    seq = (int(last.reimb_no[-4:]) + 1) if last and last.reimb_no[-4:].isdigit() else 1
    return f"{prefix}{seq:04d}"


# ============================================================
# 费用规则 CRUD
# ============================================================

@router.get("/rules")
def list_rules(
    expense_type: str = Query(None),
    status: str = Query(None),
    db: Session = Depends(get_db),
    entity_id: int = Depends(get_entity_id),
    _=Depends(require_auth),
):
    """查询费用规则列表"""
    q = db.query(ExpenseRule)
    if expense_type:
        q = q.filter(ExpenseRule.expense_type == expense_type)
    if status:
        q = q.filter(ExpenseRule.status == status)
    rules = q.order_by(ExpenseRule.id.asc()).all()
    return {"data": [_rule_to_dict(r) for r in rules], "total": len(rules)}


@router.post("/rules")
def create_rule(
    data: dict,
    db: Session = Depends(get_db),
    current_user=Depends(require_role("ceo", "finance")),
):
    """新建费用规则"""
    rule_name = data.get("rule_name")
    expense_type = data.get("expense_type")
    limit_type = data.get("limit_type", "single")
    limit_amount = data.get("limit_amount")
    if not rule_name or not expense_type or limit_amount is None:
        raise HTTPException(400, "缺少必要参数: rule_name, expense_type, limit_amount")
    if expense_type not in EXPENSE_TYPE_LABELS:
        raise HTTPException(400, f"无效费用类型: {expense_type}")
    if limit_type not in ("single", "monthly", "yearly"):
        raise HTTPException(400, f"无效限额类型: {limit_type}")

    rule = ExpenseRule(
        rule_name=rule_name,
        dimension=data.get("dimension", "expense_type"),
        dimension_value=data.get("dimension_value", "") or None,
        expense_type=expense_type,
        limit_type=limit_type,
        limit_amount=float(limit_amount),
        cycle=data.get("cycle", limit_type),
        status=data.get("status", "active"),
        remark=data.get("remark", ""),
    )
    db.add(rule)
    db.commit()
    db.refresh(rule)
    return {"message": "规则已创建", "id": rule.id}


@router.put("/rules/{rule_id}")
def update_rule(
    rule_id: int,
    data: dict,
    db: Session = Depends(get_db),
    _=Depends(require_role("ceo", "finance")),
):
    """更新费用规则"""
    rule = db.query(ExpenseRule).filter(ExpenseRule.id == rule_id).first()
    if not rule:
        raise HTTPException(404, "规则不存在")
    if "rule_name" in data and data["rule_name"]:
        rule.rule_name = data["rule_name"]
    if "expense_type" in data:
        if data["expense_type"] not in EXPENSE_TYPE_LABELS:
            raise HTTPException(400, f"无效费用类型: {data['expense_type']}")
        rule.expense_type = data["expense_type"]
    if "dimension" in data:
        rule.dimension = data["dimension"]
    if "dimension_value" in data:
        rule.dimension_value = data["dimension_value"] or None
    if "limit_type" in data:
        rule.limit_type = data["limit_type"]
    if "limit_amount" in data and data["limit_amount"] is not None:
        rule.limit_amount = float(data["limit_amount"])
    if "status" in data:
        rule.status = data["status"]
    if "remark" in data:
        rule.remark = data["remark"]
    db.commit()
    db.refresh(rule)
    return {"message": "规则已更新", "id": rule.id}


@router.delete("/rules/{rule_id}")
def delete_rule(
    rule_id: int,
    db: Session = Depends(get_db),
    _=Depends(require_role("ceo", "finance")),
):
    """删除费用规则"""
    rule = db.query(ExpenseRule).filter(ExpenseRule.id == rule_id).first()
    if not rule:
        raise HTTPException(404, "规则不存在")
    db.delete(rule)
    db.commit()
    return {"message": "规则已删除", "id": rule_id}


@router.post("/rules/seed")
def seed_rules(
    db: Session = Depends(get_db),
    _=Depends(require_role("ceo", "finance")),
):
    """预置默认费用规则（幂等，按规则名去重）"""
    created = 0
    for p in PRESET_RULES:
        exists = db.query(ExpenseRule).filter(ExpenseRule.rule_name == p["rule_name"]).first()
        if exists:
            continue
        db.add(ExpenseRule(**p))
        created += 1
    db.commit()
    return {"message": f"预置完成，新增 {created} 条规则"}


# ============================================================
# 报销单自动校验
# ============================================================

def validate_reimbursement(db: Session, reimb: ExpenseReimbursement, rules: list = None):
    """按启用规则校验报销单，写入 check_result / check_detail / check_reason

    规则匹配:
    - dimension=expense_type: 全局费用类型规则（dimension_value 可再限定具体类型）
    - dimension=department: 部门维度规则（dimension_value 空=所有部门）
    - dimension=person: 人员维度规则（dimension_value 空=所有人）
    返回 (passed: bool, checks: list)
    """
    if rules is None:
        rules = db.query(ExpenseRule).filter(ExpenseRule.status == "active").all()

    period = (reimb.expense_date or datetime.now()).strftime("%Y-%m")
    checks = []
    failed_reasons = []

    for rule in rules:
        # 费用类型必须匹配
        if rule.expense_type and rule.expense_type != reimb.expense_type:
            continue
        # 维度匹配
        if rule.dimension == "department":
            if not reimb.department:
                continue
            if rule.dimension_value and rule.dimension_value != reimb.department:
                continue
        elif rule.dimension == "person":
            if rule.dimension_value and rule.dimension_value != reimb.applicant:
                continue
        elif rule.dimension == "expense_type":
            if rule.dimension_value and rule.dimension_value != reimb.expense_type:
                continue
        else:
            continue

        actual = reimb.amount
        limit_desc = f"{rule.limit_amount:,.0f}元"

        if rule.limit_type == "single":
            passed = reimb.amount <= rule.limit_amount
            checks.append({
                "rule_id": rule.id,
                "rule_name": rule.rule_name,
                "rule_type": "单笔限额",
                "limit": rule.limit_amount,
                "actual": reimb.amount,
                "passed": passed,
                "detail": f"单笔 {reimb.amount:,.2f}元 vs 限额 {limit_desc}",
            })
        else:
            # 月度/年度累计: 统计同维度+同费用类型在周期内的已提交金额(含本次)
            q = db.query(func.coalesce(func.sum(ExpenseReimbursement.amount), 0)).filter(
                ExpenseReimbursement.expense_type == reimb.expense_type,
                ExpenseReimbursement.id != reimb.id,
                ExpenseReimbursement.status.in_(["pending", "approved"]),
            )
            if rule.limit_type == "monthly":
                q = q.filter(func.date_format(ExpenseReimbursement.expense_date, "%Y-%m") == period)
                period_label = f"{period}月"
            else:  # yearly
                year = period[:4]
                q = q.filter(func.date_format(ExpenseReimbursement.expense_date, "%Y") == year)
                period_label = f"{year}年"
            if rule.dimension == "department" and reimb.department:
                q = q.filter(ExpenseReimbursement.department == reimb.department)
            elif rule.dimension == "person":
                q = q.filter(ExpenseReimbursement.applicant == reimb.applicant)

            used = q.scalar() or 0.0
            actual = used + reimb.amount
            passed = actual <= rule.limit_amount
            checks.append({
                "rule_id": rule.id,
                "rule_name": rule.rule_name,
                "rule_type": "月度累计" if rule.limit_type == "monthly" else "年度累计",
                "limit": rule.limit_amount,
                "actual": actual,
                "used": used,
                "passed": passed,
                "detail": f"{period_label}累计 {used:,.2f} + 本次 {reimb.amount:,.2f} = {actual:,.2f}元 vs 限额 {limit_desc}",
            })

        if not passed:
            failed_reasons.append(f"{rule.rule_name}: {checks[-1]['detail']}，超限")

    passed_all = len(failed_reasons) == 0
    reimb.check_result = "pass" if passed_all else "fail"
    reimb.check_detail = checks
    reimb.check_reason = "；".join(failed_reasons) if failed_reasons else None
    reimb.checked_at = datetime.now()
    # 超限自动打回，合规进入待人工审批
    reimb.status = "pending" if passed_all else "returned"
    return passed_all, checks


# ============================================================
# 报销单提交 / 查询 / 审批
# ============================================================

@router.post("/reimbursements")
def submit_reimbursement(
    data: dict,
    db: Session = Depends(get_db),
    current_user=Depends(require_auth),
):
    """提交报销单 → 自动校验规则（超限自动打回）"""
    applicant = data.get("applicant") or (current_user.name if hasattr(current_user, "name") else current_user.username)
    expense_type = data.get("expense_type")
    title = data.get("title")
    amount = data.get("amount")

    if not expense_type or not title or amount is None:
        raise HTTPException(400, "缺少必要参数: expense_type, title, amount")
    if expense_type not in EXPENSE_TYPE_LABELS:
        raise HTTPException(400, f"无效费用类型: {expense_type}")
    amount = float(amount)
    if amount <= 0:
        raise HTTPException(400, "报销金额必须大于0")

    expense_date = None
    if data.get("expense_date"):
        try:
            expense_date = datetime.strptime(str(data["expense_date"])[:10], "%Y-%m-%d")
        except Exception:
            expense_date = None

    reimb = ExpenseReimbursement(
        reimb_no="BX" + datetime.now().strftime("%Y%m%d%H%M%S") + f"{random.randint(100, 999)}",
        applicant=applicant,
        department=data.get("department", ""),
        expense_type=expense_type,
        title=title,
        amount=amount,
        expense_date=expense_date,
        attachment=data.get("attachment", ""),
        status="pending",
        check_result="pass",
        created_by=current_user.username if hasattr(current_user, "username") else applicant,
    )
    db.add(reimb)
    db.flush()  # 先拿到 id 再生成正式单号
    reimb.reimb_no = _gen_reimb_no(db)
    db.flush()

    passed, checks = validate_reimbursement(db, reimb)
    db.commit()
    db.refresh(reimb)

    result = _reimb_to_dict(reimb)
    result["auto_check_passed"] = passed
    return {"message": "报销单已提交" if passed else "报销单超限，已自动打回", "data": result}


@router.get("/reimbursements")
def list_reimbursements(
    status: str = Query(None),
    expense_type: str = Query(None),
    applicant: str = Query(None),
    keyword: str = Query(None),
    db: Session = Depends(get_db),
    entity_id: int = Depends(get_entity_id),
    _=Depends(require_auth),
):
    """查询报销单列表（支持状态/类型/申请人/关键字筛选）"""
    q = db.query(ExpenseReimbursement)
    if status:
        q = q.filter(ExpenseReimbursement.status == status)
    if expense_type:
        q = q.filter(ExpenseReimbursement.expense_type == expense_type)
    if applicant:
        q = q.filter(ExpenseReimbursement.applicant.like(f"%{applicant}%"))
    if keyword:
        like = f"%{keyword}%"
        q = q.filter(
            (ExpenseReimbursement.title.like(like))
            | (ExpenseReimbursement.reimb_no.like(like))
            | (ExpenseReimbursement.applicant.like(like))
        )
    items = q.order_by(ExpenseReimbursement.id.desc()).limit(200).all()
    return {"data": [_reimb_to_dict(r) for r in items], "total": len(items)}


@router.get("/reimbursements/{reimb_id}")
def get_reimbursement(
    reimb_id: int,
    db: Session = Depends(get_db),
    _=Depends(require_auth),
):
    """报销单详情"""
    r = db.query(ExpenseReimbursement).filter(ExpenseReimbursement.id == reimb_id).first()
    if not r:
        raise HTTPException(404, "报销单不存在")
    return _reimb_to_dict(r)


def _do_approve(db: Session, reimb_id: int, action: str, comment: str, approver: str):
    """执行审批动作: approve/reject/return"""
    r = db.query(ExpenseReimbursement).filter(ExpenseReimbursement.id == reimb_id).first()
    if not r:
        raise HTTPException(404, "报销单不存在")
    if r.status not in ("pending", "returned"):
        raise HTTPException(400, f"当前状态({r.status})不可审批")

    if action == "approve":
        r.status = "approved"
    elif action == "reject":
        r.status = "rejected"
    else:
        r.status = "returned"
    r.approver = approver
    r.approve_comment = comment or ("" if action == "approve" else "人工打回")
    r.approved_at = datetime.now()
    db.commit()
    db.refresh(r)
    return r


@router.post("/reimbursements/{reimb_id}/approve")
def approve_reimbursement(
    reimb_id: int,
    data: dict = None,
    db: Session = Depends(get_db),
    current_user=Depends(require_role("ceo", "finance")),
):
    """审批通过"""
    approver = current_user.name if hasattr(current_user, "name") else current_user.username
    r = _do_approve(db, reimb_id, "approve", (data or {}).get("comment", ""), approver)
    return {"message": "已审批通过", "data": _reimb_to_dict(r)}


@router.post("/reimbursements/{reimb_id}/reject")
def reject_reimbursement(
    reimb_id: int,
    data: dict = None,
    db: Session = Depends(get_db),
    current_user=Depends(require_role("ceo", "finance")),
):
    """审批拒绝"""
    comment = (data or {}).get("comment", "")
    if not comment:
        raise HTTPException(400, "拒绝时必须填写审批意见")
    approver = current_user.name if hasattr(current_user, "name") else current_user.username
    r = _do_approve(db, reimb_id, "reject", comment, approver)
    return {"message": "已拒绝", "data": _reimb_to_dict(r)}


@router.post("/reimbursements/{reimb_id}/return")
def return_reimbursement(
    reimb_id: int,
    data: dict = None,
    db: Session = Depends(get_db),
    current_user=Depends(require_role("ceo", "finance")),
):
    """人工打回"""
    approver = current_user.name if hasattr(current_user, "name") else current_user.username
    r = _do_approve(db, reimb_id, "return", (data or {}).get("comment", "人工打回"), approver)
    return {"message": "已打回", "data": _reimb_to_dict(r)}


@router.post("/reimbursements/{reimb_id}/resubmit")
def resubmit_reimbursement(
    reimb_id: int,
    data: dict = None,
    db: Session = Depends(get_db),
    _=Depends(require_auth),
):
    """被驳回/打回后重新提交 → 重新自动校验"""
    r = db.query(ExpenseReimbursement).filter(ExpenseReimbursement.id == reimb_id).first()
    if not r:
        raise HTTPException(404, "报销单不存在")
    if r.status not in ("returned", "rejected"):
        raise HTTPException(400, f"当前状态({r.status})不可重新提交")

    # 允许修改金额/事由后重新校验
    if data:
        if data.get("amount") is not None:
            r.amount = float(data["amount"])
        if data.get("title"):
            r.title = data["title"]
        if data.get("attachment") is not None:
            r.attachment = data["attachment"]

    passed, _ = validate_reimbursement(db, r)
    r.approver = None
    r.approve_comment = None
    db.commit()
    db.refresh(r)
    return {"message": "已重新提交" if passed else "仍超限，已再次打回", "data": _reimb_to_dict(r)}


# ============================================================
# 审核看板统计
# ============================================================

@router.get("/stats")
def expense_stats(
    period: str = Query(None, description="期间 YYYY-MM，默认当前月"),
    db: Session = Depends(get_db),
    _=Depends(require_auth),
):
    """费用审核看板统计: 状态计数 / 费用类型统计 / 超限预警 / 本月总额"""
    now = datetime.now()
    period = period or now.strftime("%Y-%m")

    counts = {"pending": 0, "approved": 0, "rejected": 0, "returned": 0, "total": 0}
    for st, cnt in db.query(ExpenseReimbursement.status, func.count(ExpenseReimbursement.id)).group_by(
        ExpenseReimbursement.status
    ).all():
        if st in counts:
            counts[st] = cnt
        counts["total"] += cnt

    # 本月(按费用发生日期)金额统计 by 费用类型 — 统计已提交(待审+已通过)
    month_rows = (
        db.query(
            ExpenseReimbursement.expense_type,
            func.coalesce(func.sum(ExpenseReimbursement.amount), 0),
            func.count(ExpenseReimbursement.id),
        )
        .filter(
            ExpenseReimbursement.status.in_(["pending", "approved"]),
            func.date_format(ExpenseReimbursement.expense_date, "%Y-%m") == period,
        )
        .group_by(ExpenseReimbursement.expense_type)
        .all()
    )
    amounts_by_type = [
        {
            "expense_type": et,
            "label": EXPENSE_TYPE_LABELS.get(et, et),
            "amount": round(float(amt), 2),
            "count": cnt,
        }
        for et, amt, cnt in month_rows
    ]

    monthly_total = round(sum(x["amount"] for x in amounts_by_type), 2)

    # 超限预警列表 — 自动打回(returned + check_result=fail)
    over_limit_rows = (
        db.query(ExpenseReimbursement)
        .filter(
            ExpenseReimbursement.status == "returned",
            ExpenseReimbursement.check_result == "fail",
        )
        .order_by(ExpenseReimbursement.id.desc())
        .limit(50)
        .all()
    )
    over_limit = [
        {
            "id": r.id,
            "reimb_no": r.reimb_no,
            "applicant": r.applicant,
            "department": r.department,
            "expense_type": r.expense_type,
            "expense_type_label": EXPENSE_TYPE_LABELS.get(r.expense_type, r.expense_type),
            "title": r.title,
            "amount": r.amount,
            "check_reason": r.check_reason,
            "created_at": r.created_at.isoformat() if r.created_at else None,
        }
        for r in over_limit_rows
    ]

    recent_rows = db.query(ExpenseReimbursement).order_by(ExpenseReimbursement.id.desc()).limit(10).all()
    recent = [_reimb_to_dict(r) for r in recent_rows]

    # 本月预算使用率(招待费15万/月 管理费91万/月)
    budget_usage = []
    for et, budget in (("entertainment", 150000.0), ("management", 910000.0)):
        used = next((x["amount"] for x in amounts_by_type if x["expense_type"] == et), 0.0)
        budget_usage.append({
            "expense_type": et,
            "label": EXPENSE_TYPE_LABELS.get(et, et),
            "budget": budget,
            "used": used,
            "usage_rate": round(used / budget * 100, 1) if budget else 0,
        })

    return {
        "period": period,
        "counts": counts,
        "amounts_by_type": amounts_by_type,
        "monthly_total": monthly_total,
        "over_limit": over_limit,
        "over_limit_count": len(over_limit),
        "recent": recent,
        "budget_usage": budget_usage,
    }
