"""预算管理 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,
    }


# ──────────────────────────────────────────────
# 功能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": "零基预算",
    }
