"""预算管理 API — 管理会计OS
预算值的CRUD、自动分解、版本管理
"""
from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.orm import Session
from sqlalchemy import func
from typing import Optional
from datetime import datetime

from app.database import get_db
from app.auth_middleware import require_auth, require_role
from app.models import BudgetPlan, KPIDefinition, OperationLog

router = APIRouter(prefix="/api/cma/budget", tags=["预算管理"],
    dependencies=[Depends(require_role("ceo", "finance", "it"))],
)


@router.get("/plans")
def list_budget_plans(
    kpi_id: Optional[int] = Query(None),
    period: Optional[str] = Query(None),
    year: Optional[int] = Query(None),
    version: Optional[str] = Query(None),
    db: Session = Depends(get_db),
):
    """查询预算计划列表"""
    query = db.query(BudgetPlan).join(
        KPIDefinition, BudgetPlan.kpi_id == KPIDefinition.id
    )

    if kpi_id:
        query = query.filter(BudgetPlan.kpi_id == kpi_id)
    if period:
        query = query.filter(BudgetPlan.period == period)
    if year:
        query = query.filter(BudgetPlan.budget_year == year)
    if version:
        query = query.filter(BudgetPlan.version == version)

    plans = query.order_by(BudgetPlan.budget_year.desc(), BudgetPlan.budget_month.asc()).all()

    result = []
    for p in plans:
        kpi = db.query(KPIDefinition).filter(KPIDefinition.id == p.kpi_id).first()
        result.append({
            "id": p.id,
            "kpi_id": p.kpi_id,
            "kpi_code": kpi.kpi_code if kpi else "",
            "kpi_name": kpi.kpi_name if kpi else "",
            "period": p.period,
            "budget_value": p.budget_value,
            "budget_year": p.budget_year,
            "budget_month": p.budget_month,
            "version": p.version,
            "status": p.status,
            "remark": p.remark,
            "created_at": p.created_at.isoformat() if p.created_at else None,
        })
    return {"data": result, "total": len(result)}


@router.post("/plans")
def create_budget_plan(
    data: dict,
    db: Session = Depends(get_db),
    current_user=Depends(require_auth),
):
    """创建或更新单条预算计划"""
    kpi_id = data.get("kpi_id")
    period = data.get("period")
    budget_value = data.get("budget_value")

    if not all([kpi_id, period, budget_value is not None]):
        raise HTTPException(400, "缺少必要参数: kpi_id, period, budget_value")

    # 检查KPI是否存在
    kpi = db.query(KPIDefinition).filter(KPIDefinition.id == kpi_id).first()
    if not kpi:
        raise HTTPException(404, "KPI不存在")

    year, month = period.split("-")
    version = data.get("version", "v1.0")

    # 检查是否已有记录（去重）
    existing = db.query(BudgetPlan).filter(
        BudgetPlan.kpi_id == kpi_id,
        BudgetPlan.period == period,
        BudgetPlan.version == version,
        BudgetPlan.status == "active",
    ).first()

    if existing:
        existing.budget_value = budget_value
        existing.remark = data.get("remark", existing.remark)
        db.commit()
        db.refresh(existing)
        return {"message": "预算已更新", "id": existing.id}
    else:
        plan = BudgetPlan(
            kpi_id=kpi_id,
            period=period,
            budget_value=budget_value,
            budget_year=int(year),
            budget_month=int(month),
            version=version,
            status="active",
            remark=data.get("remark", ""),
            created_by=current_user.name if hasattr(current_user, "name") else "",
        )
        db.add(plan)
        db.commit()
        db.refresh(plan)

        # 记录操作日志
        log = OperationLog(
            action="create",
            target_type="budget",
            target_id=plan.id,
            detail=__import__("json").dumps({"kpi_id": kpi_id, "period": period, "value": budget_value}, ensure_ascii=False),
        )
        db.add(log)
        db.commit()

        return {"message": "预算已创建", "id": plan.id}


@router.put("/plans/{plan_id}")
def update_budget_plan(
    plan_id: int,
    data: dict,
    db: Session = Depends(get_db),
):
    """更新预算计划"""
    plan = db.query(BudgetPlan).filter(BudgetPlan.id == plan_id).first()
    if not plan:
        raise HTTPException(404, "预算计划不存在")

    if "budget_value" in data:
        plan.budget_value = data["budget_value"]
    if "remark" in data:
        plan.remark = data["remark"]
    if "version" in data:
        plan.version = data["version"]
    if "status" in data:
        plan.status = data["status"]

    db.commit()
    return {"message": "预算已更新"}


@router.delete("/plans/{plan_id}")
def delete_budget_plan(
    plan_id: int,
    db: Session = Depends(get_db),
):
    """删除预算计划"""
    plan = db.query(BudgetPlan).filter(BudgetPlan.id == plan_id).first()
    if not plan:
        raise HTTPException(404, "预算计划不存在")
    db.delete(plan)
    db.commit()
    return {"message": "预算已删除"}


@router.post("/auto-decompose")
def auto_decompose_budget(
    data: dict,
    db: Session = Depends(get_db),
    current_user=Depends(require_auth),
):
    """自动分解年度预算到月度（均分或按历史权重）"""
    kpi_id = data.get("kpi_id")
    year = data.get("year", datetime.now().year)
    annual_budget = data.get("annual_budget")
    method = data.get("method", "equal")  # equal / weighted
    version = data.get("version", "v1.0")

    if not kpi_id or annual_budget is None:
        raise HTTPException(400, "缺少必要参数: kpi_id, annual_budget")

    kpi = db.query(KPIDefinition).filter(KPIDefinition.id == kpi_id).first()
    if not kpi:
        raise HTTPException(404, "KPI不存在")

    # 计算各月权重
    if method == "weighted":
        # 按去年各月实际值的比例分配
        last_year = year - 1
        values = db.query(KPIValue).filter(
            KPIValue.kpi_id == kpi_id,
            KPIValue.period.like(f"{last_year}-%"),
            KPIValue.actual_value.isnot(None),
        ).order_by(KPIValue.period.asc()).all()

        total = sum(v.actual_value for v in values)
        if total > 0:
            weights = {v.period: v.actual_value / total for v in values}
        else:
            method = "equal"
        created = []
        for m in range(1, 13):
            period = f"{year}-{m:02d}"
            weight = weights.get(period, 1 / 12) if method == "weighted" else 1 / 12
            monthly_value = round(annual_budget * weight, 2)

            existing = db.query(BudgetPlan).filter(
                BudgetPlan.kpi_id == kpi_id,
                BudgetPlan.period == period,
                BudgetPlan.version == version,
                BudgetPlan.status == "active",
            ).first()

            if existing:
                existing.budget_value = monthly_value
            else:
                bp = BudgetPlan(
                    kpi_id=kpi_id, period=period,
                    budget_value=monthly_value, budget_year=year,
                    budget_month=m, version=version, status="active",
                    created_by=current_user.name if hasattr(current_user, "name") else "",
                )
                db.add(bp)
            created.append({"period": period, "value": monthly_value})
    else:
        # 均分
        monthly = round(annual_budget / 12, 2)
        created = []
        for m in range(1, 13):
            period = f"{year}-{m:02d}"
            existing = db.query(BudgetPlan).filter(
                BudgetPlan.kpi_id == kpi_id,
                BudgetPlan.period == period,
                BudgetPlan.version == version,
                BudgetPlan.status == "active",
            ).first()
            if existing:
                existing.budget_value = monthly
            else:
                bp = BudgetPlan(
                    kpi_id=kpi_id, period=period,
                    budget_value=monthly, budget_year=year,
                    budget_month=m, version=version, status="active",
                    created_by=current_user.name if hasattr(current_user, "name") else "",
                )
                db.add(bp)
            created.append({"period": period, "value": monthly})

    db.commit()
    return {
        "message": f"年度预算已分解为{len(created)}个月度预算",
        "kpi_id": kpi_id,
        "kpi_name": kpi.kpi_name,
        "year": year,
        "annual_budget": annual_budget,
        "method": method,
        "monthly_budgets": created,
    }


@router.get("/deviation-report")
def get_deviation_report(
    kpi_id: Optional[int] = Query(None),
    period: Optional[str] = Query(None),
    year: Optional[int] = Query(None),
    month: Optional[int] = Query(None),
    dimension: Optional[str] = Query(None),
    alert_level: Optional[str] = Query(None),
    db: Session = Depends(get_db),
):
    """获取差异分析报告（汇总多个KPI的实际vs预算差异）"""
    if period is None:
        if year and month:
            period = f"{year}-{month:02d}"
        elif year:
            period = f"{year}-{datetime.now().month:02d}"
        else:
            period = datetime.now().strftime("%Y-%m")

    query = db.query(KPIDefinition).filter(KPIDefinition.status == "active")
    if kpi_id:
        query = query.filter(KPIDefinition.id == kpi_id)
    if dimension:
        query = query.filter(KPIDefinition.dimension == dimension)

    kpis = query.all()
    from app.utils.deviation_engine import calc_period_deviation, calc_period_diff

    items = []
    summary = {
        "total_kpis": 0,
        "has_budget": 0,
        "over_budget": 0,
        "under_budget": 0,
        "avg_deviation_rate": 0,
    }

    rates = []
    for kpi in kpis:
        item = calc_period_deviation(db, kpi.id, period)
        items.append(item)
        summary["total_kpis"] += 1

        if item.get("budget_value") is not None:
            summary["has_budget"] += 1
        if item.get("is_over_budget"):
            summary["over_budget"] += 1
        elif item.get("deviation_rate") is not None and item["deviation_rate"] < 0:
            summary["under_budget"] += 1
        if item.get("deviation_rate") is not None:
            rates.append(abs(item["deviation_rate"]))

        # 补充同比/环比
        if item.get("actual_value") is not None:
            item["yoy"] = calc_period_diff(db, kpi.id, period, "yoy")
            item["mom"] = calc_period_diff(db, kpi.id, period, "mom")

    summary["avg_deviation_rate"] = round(sum(rates) / len(rates), 2) if rates else 0

    # 前端 alert_level 过滤
    if alert_level:
        def get_level(rate):
            if rate is None:
                return None
            if rate > 20:
                return "red"
            if rate > 10:
                return "yellow"
            return "normal"
        items = [i for i in items if get_level(i.get("deviation_rate")) == alert_level]

    return {
        "period": period,
        "summary": summary,
        "items": items,
    }


# ──────────────────────────────────────────────
# 滚动/固定预算切换
# ──────────────────────────────────────────────

@router.get("/config")
def get_budget_config(db: Session = Depends(get_db)):
    """获取预算模式配置"""
    from app.models import SystemConfig
    cfg = db.query(SystemConfig).filter(SystemConfig.config_key == "budget_mode").first()
    if not cfg:
        return {"budget_mode": "fixed", "rolling_months": 12, "description": "固定预算（年度）"}
    import json
    try:
        val = json.loads(cfg.config_value)
    except (json.JSONDecodeError, TypeError):
        val = {"mode": "fixed", "rolling_months": 12}
    return val


@router.post("/config")
def set_budget_config(
    data: dict,
    db: Session = Depends(get_db),
    current_user=Depends(require_auth),
):
    """设置预算模式"""
    from app.models import SystemConfig
    import json

    mode = data.get("mode", "fixed")
    rolling_months = data.get("rolling_months", 12)
    if mode not in ("fixed", "rolling"):
        raise HTTPException(400, "预算模式必须是 fixed 或 rolling")

    cfg = db.query(SystemConfig).filter(SystemConfig.config_key == "budget_mode").first()
    val = json.dumps({"mode": mode, "rolling_months": rolling_months}, ensure_ascii=False)
    if cfg:
        cfg.config_value = val
    else:
        cfg = SystemConfig(
            config_key="budget_mode",
            config_value=val,
            description="预算模式: fixed=固定预算, rolling=滚动预算",
        )
        db.add(cfg)
    db.commit()
    return {"message": f"预算模式已切换为{'滚动预算' if mode == 'rolling' else '固定预算'}", "budget_mode": mode, "rolling_months": rolling_months}


# ──────────────────────────────────────────────
# 滚动预算自动延展
# ──────────────────────────────────────────────

@router.post("/roll-forward")
def budget_roll_forward(
    db: Session = Depends(get_db),
    current_user=Depends(require_auth),
):
    """
    滚动预算自动延展：
    - 删除最早一个月的预测数据
    - 新增未来一个月的预测数据（取最近三个月均值）
    - 返回延展结果
    """
    from app.models import SystemConfig
    cfg = db.query(SystemConfig).filter(SystemConfig.config_key == "budget_mode").first()
    import json
    if not cfg:
        raise HTTPException(400, "未配置预算模式，请先设置")
    try:
        val = json.loads(cfg.config_value)
    except (json.JSONDecodeError, TypeError):
        raise HTTPException(400, "预算模式配置异常")

    if val.get("mode") != "rolling":
        raise HTTPException(400, "当前为固定预算模式，无需延展")

    now = datetime.now()
    current_year, current_month = now.year, now.month

    # 获取所有active的预算记录
    plans = db.query(BudgetPlan).filter(BudgetPlan.status == "active").all()

    # 按KPI分组
    from collections import defaultdict
    kpi_plans = defaultdict(list)
    for p in plans:
        kpi_plans[p.kpi_id].append(p)

    rolled_kpis = []
    for kpi_id, p_list in kpi_plans.items():
        # 按期间排序
        p_list.sort(key=lambda x: (x.budget_year, x.budget_month))

        # 找出最早的一个月并删除
        if p_list:
            oldest = p_list[0]
            db.query(BudgetPlan).filter(BudgetPlan.id == oldest.id).delete()

        # 计算新增月份的预算值（取最近三个月均值）
        recent_values = [p.budget_value for p in p_list[-3:]] if len(p_list) >= 3 else [p.budget_value for p in p_list]
        avg_value = round(sum(recent_values) / len(recent_values), 2) if recent_values else 0

        # 计算新的月份（当前月 + 12个月后）
        new_year = current_year
        new_month = current_month + val.get("rolling_months", 12)
        while new_month > 12:
            new_month -= 12
            new_year += 1

        new_period = f"{new_year}-{new_month:02d}"

        # 检查是否已存在
        existing = db.query(BudgetPlan).filter(
            BudgetPlan.kpi_id == kpi_id,
            BudgetPlan.period == new_period,
            BudgetPlan.status == "active",
        ).first()

        if not existing:
            bp = BudgetPlan(
                kpi_id=kpi_id,
                period=new_period,
                budget_value=avg_value,
                budget_year=new_year,
                budget_month=new_month,
                version="rolling",
                status="active",
                remark=f"滚动延展自{current_year}-{current_month:02d}",
                created_by=current_user.name if hasattr(current_user, "name") else "",
            )
            db.add(bp)
            rolled_kpis.append({
                "kpi_id": kpi_id,
                "removed_period": f"{p_list[0].budget_year}-{p_list[0].budget_month:02d}" if p_list else None,
                "added_period": new_period,
                "predicted_value": avg_value,
            })

    db.commit()
    return {
        "message": f"滚动预算已延展，处理了 {len(rolled_kpis)} 个KPI",
        "rolled_kpis": rolled_kpis,
        "current_month": f"{current_year}-{current_month:02d}",
        "rolling_months": val.get("rolling_months", 12),
    }


# ──────────────────────────────────────────────
# 实际vs预测对比
# ──────────────────────────────────────────────

@router.get("/comparison")
def get_budget_comparison(
    kpi_id: Optional[int] = Query(None),
    year: Optional[int] = Query(None),
    db: Session = Depends(get_db),
):
    """
    获取实际值vs预测值对比数据
    返回：各月预算值、实际值、偏差率，以及分界点标记
    """
    from app.models import KPIValue, SystemConfig
    import json

    now = datetime.now()
    y = year or now.year

    # 判断预算模式
    cfg = db.query(SystemConfig).filter(SystemConfig.config_key == "budget_mode").first()
    budget_mode = "fixed"
    rolling_months = 12
    if cfg:
        try:
            val = json.loads(cfg.config_value)
            budget_mode = val.get("mode", "fixed")
            rolling_months = val.get("rolling_months", 12)
        except (json.JSONDecodeError, TypeError):
            pass

    # 确定查询的月份范围
    if budget_mode == "rolling":
        # 滚动预算：从当月起的 rolling_months 个月
        start_year, start_month = now.year, now.month
        periods = []
        for i in range(rolling_months):
            m = start_month + i
            yy = start_year
            while m > 12:
                m -= 12
                yy += 1
            periods.append(f"{yy}-{m:02d}")
    else:
        # 固定预算：全年1-12月
        periods = [f"{y}-{m:02d}" for m in range(1, 13)]

    # 查询预算数据
    query = db.query(BudgetPlan).join(
        KPIDefinition, BudgetPlan.kpi_id == KPIDefinition.id
    )
    if kpi_id:
        query = query.filter(BudgetPlan.kpi_id == kpi_id)
    query = query.filter(BudgetPlan.period.in_(periods), BudgetPlan.status == "active")
    budget_plans = query.all()

    # 按KPI+期间索引
    bp_map = {}
    for bp in budget_plans:
        key = (bp.kpi_id, bp.period)
        bp_map[key] = bp.budget_value

    # 查询实际值
    kpi_ids = set(bp.kpi_id for bp in budget_plans)
    actual_values = {}
    if kpi_ids:
        values = db.query(KPIValue).filter(
            KPIValue.kpi_id.in_(kpi_ids),
            KPIValue.period.in_(periods),
            KPIValue.actual_value.isnot(None),
        ).all()
        for v in values:
            key = (v.kpi_id, v.period)
            actual_values[key] = v.actual_value

    # 构建对比数据
    now_period = now.strftime("%Y-%m")
    months_data = []
    for period in periods:
        monthly = {"period": period, "is_current_period": period == now_period}
        total_budget = 0
        total_actual = 0
        count_budget = 0
        count_actual = 0
        for kpi_id_item in kpi_ids:
            bp_key = (kpi_id_item, period)
            if bp_key in bp_map:
                total_budget += bp_map[bp_key] or 0
                count_budget += 1
            if bp_key in actual_values:
                total_actual += actual_values[bp_key] or 0
                count_actual += 1

        monthly["budget_total"] = round(total_budget, 2)
        monthly["actual_total"] = round(total_actual, 2)
        monthly["kpi_count"] = len(kpi_ids)

        # 分界点标记
        if budget_mode == "rolling":
            # 滚动预算下，当前月之后为预测值
            monthly["is_prediction"] = period > now_period
        else:
            monthly["is_prediction"] = period > now_period

        # 偏差率
        if monthly["budget_total"] and monthly["budget_total"] > 0:
            monthly["deviation_rate"] = round(
                (monthly["actual_total"] - monthly["budget_total"]) / monthly["budget_total"] * 100, 2
            ) if monthly["actual_total"] is not None else None
        else:
            monthly["deviation_rate"] = None

        months_data.append(monthly)

    return {
        "periods": periods,
        "budget_mode": budget_mode,
        "year": y,
        "current_period": now_period,
        "months_data": months_data,
        "total_kpis": len(kpi_ids),
    }


@router.get("/comparison/kpi/{kpi_id}")
def get_kpi_comparison(
    kpi_id: int,
    year: Optional[int] = Query(None),
    db: Session = Depends(get_db),
):
    """
    获取单个KPI的实际vs预测对比数据（用于图表展示）
    """
    from app.models import KPIValue, SystemConfig
    import json

    now = datetime.now()
    y = year or now.year

    kpi = db.query(KPIDefinition).filter(KPIDefinition.id == kpi_id).first()
    if not kpi:
        raise HTTPException(404, "KPI不存在")

    periods = [f"{y}-{m:02d}" for m in range(1, 13)]

    # 预算值
    budgets = db.query(BudgetPlan).filter(
        BudgetPlan.kpi_id == kpi_id,
        BudgetPlan.period.in_(periods),
        BudgetPlan.status == "active",
    ).all()
    budget_map = {bp.period: bp.budget_value for bp in budgets}

    # 实际值
    actuals = db.query(KPIValue).filter(
        KPIValue.kpi_id == kpi_id,
        KPIValue.period.in_(periods),
        KPIValue.actual_value.isnot(None),
    ).all()
    actual_map = {av.period: av.actual_value for av in actuals}

    now_period = now.strftime("%Y-%m")
    data_points = []
    for period in periods:
        bv = budget_map.get(period)
        av = actual_map.get(period)
        dr = None
        if bv and bv > 0 and av is not None:
            dr = round((av - bv) / bv * 100, 2)

        data_points.append({
            "period": period,
            "budget_value": bv,
            "actual_value": av,
            "deviation_rate": dr,
            "is_prediction": period > now_period,
            "is_current_period": period == now_period,
        })

    return {
        "kpi_id": kpi.id,
        "kpi_code": kpi.kpi_code,
        "kpi_name": kpi.kpi_name,
        "unit": kpi.unit or "",
        "year": y,
        "current_period": now_period,
        "data_points": data_points,
    }


# ──────────────────────────────────────────────
# 预测偏差告警
# ──────────────────────────────────────────────

@router.post("/deviation-check")
def check_budget_deviation(
    data: dict,
    db: Session = Depends(get_db),
    current_user=Depends(require_auth),
):
    """
    检查实际vs预测偏差，当偏差超过20%时自动生成预警
    """
    from app.models import KPIValue, BudgetDeviationAlert
    from sqlalchemy import func

    threshold = data.get("threshold", 20)  # 默认20%
    period = data.get("period") or datetime.now().strftime("%Y-%m")
    auto_resolve = data.get("auto_resolve", True)  # 是否自动关闭已解决的预警

    # 查询该期间的有预算的KPI
    budget_plans = db.query(BudgetPlan).filter(
        BudgetPlan.period == period,
        BudgetPlan.status == "active",
    ).all()

    if not budget_plans:
        return {
            "message": f"期间 {period} 无预算数据",
            "alerts_generated": 0,
            "alerts": [],
        }

    alerts_generated = 0
    alerts = []

    for bp in budget_plans:
        # 查询实际值
        actual = db.query(KPIValue).filter(
            KPIValue.kpi_id == bp.kpi_id,
            KPIValue.period == period,
            KPIValue.actual_value.isnot(None),
        ).first()

        if not actual or actual.actual_value is None:
            continue

        budget_val = bp.budget_value
        actual_val = actual.actual_value

        if budget_val == 0:
            continue

        # 计算偏差率
        deviation_rate = round((actual_val - budget_val) / budget_val * 100, 2)

        # 只有偏差超过阈值才生成预警
        if abs(deviation_rate) <= threshold:
            continue

        deviation_value = round(actual_val - budget_val, 2)

        # 判断预警等级
        alert_level = "critical" if abs(deviation_rate) > 50 else "warning"

        # 生成建议
        if deviation_rate > 0:
            suggestion = f"实际值超出预算 {deviation_rate}%，建议核查超支原因并采取控制措施"
        else:
            suggestion = f"实际值低于预算 {abs(deviation_rate)}%，建议分析是否预算过高或业务量未达预期"

        # 检查是否已存在相同的预警
        existing_alert = db.query(BudgetDeviationAlert).filter(
            BudgetDeviationAlert.kpi_id == bp.kpi_id,
            BudgetDeviationAlert.period == period,
            BudgetDeviationAlert.status == "open",
        ).first()

        if existing_alert:
            continue

        alert = BudgetDeviationAlert(
            kpi_id=bp.kpi_id,
            period=period,
            budget_value=budget_val,
            actual_value=actual_val,
            deviation_rate=deviation_rate,
            deviation_value=deviation_value,
            alert_level=alert_level,
            status="open",
            suggestion=suggestion,
        )
        db.add(alert)
        alerts_generated += 1

        kpi_obj = db.query(KPIDefinition).filter(KPIDefinition.id == bp.kpi_id).first()
        alerts.append({
            "kpi_id": bp.kpi_id,
            "kpi_code": kpi_obj.kpi_code if kpi_obj else "",
            "kpi_name": kpi_obj.kpi_name if kpi_obj else "",
            "period": period,
            "budget_value": budget_val,
            "actual_value": actual_val,
            "deviation_rate": deviation_rate,
            "deviation_value": deviation_value,
            "alert_level": alert_level,
            "suggestion": suggestion,
        })

    db.commit()

    return {
        "message": f"检查完成，生成了 {alerts_generated} 条预警",
        "period": period,
        "threshold": threshold,
        "alerts_generated": alerts_generated,
        "alerts": alerts,
    }


@router.get("/deviation-alerts")
def list_deviation_alerts(
    kpi_id: Optional[int] = Query(None),
    period: Optional[str] = Query(None),
    alert_level: Optional[str] = Query(None),
    status: Optional[str] = Query(None),
    db: Session = Depends(get_db),
):
    """查询预算偏差预警记录"""
    from app.models import BudgetDeviationAlert
    query = db.query(BudgetDeviationAlert)
    if kpi_id:
        query = query.filter(BudgetDeviationAlert.kpi_id == kpi_id)
    if period:
        query = query.filter(BudgetDeviationAlert.period == period)
    if alert_level:
        query = query.filter(BudgetDeviationAlert.alert_level == alert_level)
    if status:
        query = query.filter(BudgetDeviationAlert.status == status)

    alerts = query.order_by(BudgetDeviationAlert.created_at.desc()).all()
    result = []
    for a in alerts:
        kpi_obj = db.query(KPIDefinition).filter(KPIDefinition.id == a.kpi_id).first()
        result.append({
            "id": a.id,
            "kpi_id": a.kpi_id,
            "kpi_code": kpi_obj.kpi_code if kpi_obj else "",
            "kpi_name": kpi_obj.kpi_name if kpi_obj else "",
            "period": a.period,
            "budget_value": a.budget_value,
            "actual_value": a.actual_value,
            "deviation_rate": a.deviation_rate,
            "deviation_value": a.deviation_value,
            "alert_level": a.alert_level,
            "status": a.status,
            "suggestion": a.suggestion,
            "created_at": a.created_at.isoformat() if a.created_at else None,
        })
    return {"data": result, "total": len(result)}


@router.put("/deviation-alerts/{alert_id}")
def update_deviation_alert(
    alert_id: int,
    data: dict,
    db: Session = Depends(get_db),
):
    """更新偏差预警（如标记已解决）"""
    from app.models import BudgetDeviationAlert
    alert = db.query(BudgetDeviationAlert).filter(BudgetDeviationAlert.id == alert_id).first()
    if not alert:
        raise HTTPException(404, "预警记录不存在")
    if "status" in data:
        alert.status = data["status"]
    db.commit()
    return {"message": "预警已更新"}


# ──────────────────────────────────────────────
# 功能6: 预算方法三选一向导 (CMA P1 - 增量/零基/弹性)
# ──────────────────────────────────────────────

@router.post("/method-comparison")
def budget_method_comparison(data: dict):
    """
    预算方法三选一对比计算
    接收: { entity: "hanke", last_month_budget: 91, current_revenue: 122, ... }
    返回三种方法的计算结果
    """
    entity = data.get("entity", "hanke")
    last_month_budget = data.get("last_month_budget", 91)  # 上月预算（万）
    current_revenue = data.get("current_revenue", 122)  # 当前收入（万）
    fixed_costs = data.get("fixed_costs", {
        "rent": 15,       # 房租（万）
        "labor": 40,      # 人工（万）
        "entertainment": 16,  # 招待费（万）
        "misc": 12,       # 杂项（万）
    })
    variable_cost_rate = data.get("variable_cost_rate", 0.4862)  # 变动成本率

    # 1. 增量预算: 基于上月统一调整
    increment_rate = data.get("increment_rate", 0.05)  # 5%增幅
    incremental_result = round(last_month_budget * (1 + increment_rate), 1)
    incremental_detail = f"上月{last_month_budget}万 × (1+{increment_rate*100:.0f}%) = {incremental_result}万"

    # 2. 零基预算: 每项从零论证
    zbb_entertainment = round(fixed_costs.get("entertainment", 16) / 2, 1)  # 砍半
    zbb_misc = round(fixed_costs.get("misc", 12) * 0.7, 1)  # 压缩30%
    zbb_total = round(
        fixed_costs.get("rent", 15)
        + fixed_costs.get("labor", 40)
        + zbb_entertainment
        + zbb_misc,
        1,
    )
    zbb_savings = round(last_month_budget - zbb_total, 1)
    zbb_detail = (
        f"房租{fixed_costs.get('rent', 15)}万(固定)+人工{fixed_costs.get('labor', 40)}万(砍不掉)"
        f"+招待{zbb_entertainment}万(砍半)+杂项{zbb_misc}万(压缩)"
        f"={zbb_total}万 ← 省{zbb_savings}万"
    )

    # 3. 弹性预算: 根据收入水平动态调整
    flexible_fixed = round(fixed_costs.get("rent", 15) + fixed_costs.get("labor", 40) * 0.5, 1)
    flexible_variable = round(current_revenue * variable_cost_rate * 0.4, 1)
    flexible_total = round(flexible_fixed + flexible_variable, 1)
    flexible_variance = round(last_month_budget - flexible_total, 1)
    flex_detail = (
        f"收入{current_revenue}万 → 对应费用预算 = {flexible_total}万"
        f"（固定部分{flexible_fixed}万+变动部分{flexible_variable}万）"
        f"，实际{last_month_budget}万 → 差异{flexible_variance}万 → {'效率问题' if flexible_variance > 0 else '节省'}"
    )

    # 推荐方法
    recommended = "zero_based"

    return {
        "entity": entity,
        "entity_name": "陕西酣客（白酒经销）" if entity == "hanke" else "陕西博海科技（IT服务）",
        "methods": [
            {
                "id": "incremental",
                "name": "增量预算",
                "name_en": "Incremental Budgeting",
                "result_value": incremental_result,
                "detail": incremental_detail,
                "pros": "简单快速",
                "cons": "浪费持续",
                "is_recommended": False,
            },
            {
                "id": "zero_based",
                "name": "零基预算",
                "name_en": "Zero-Based Budgeting (ZBB)",
                "result_value": zbb_total,
                "savings": zbb_savings,
                "detail": zbb_detail,
                "pros": "最合理",
                "cons": "耗时",
                "is_recommended": True,
            },
            {
                "id": "flexible",
                "name": "弹性预算",
                "name_en": "Flexible Budgeting",
                "result_value": flexible_total,
                "variance": flexible_variance,
                "detail": flex_detail,
                "pros": "动态响应",
                "cons": "需要详细分类",
                "is_recommended": False,
            },
        ],
        "recommended": recommended,
        "recommended_name": "零基预算",
    }
