"""资金管理API — 资金缺口预测 + 收付款计划 + 预警 (资金管理智能体)"""
import logging
from datetime import datetime, timedelta
from fastapi import APIRouter, HTTPException, Depends, Query
from sqlalchemy.orm import Session
from app.database import get_db
from app.auth_middleware import require_role
from app.models import CashPlan
from app.utils.cash_forecast_engine import (
    forecast_cash_flow_with_plans,
    check_cash_alerts,
    DEFAULT_CASH_WARNING,
    DEFAULT_CASH_CRITICAL,
)

logger = logging.getLogger("cma.cash")

router = APIRouter(
    prefix="/api/cma/cash",
    tags=["资金管理"],
    dependencies=[Depends(require_role("ceo", "finance", "business", "it"))],
)


def _plan_dict(p: CashPlan) -> dict:
    return {
        "id": p.id,
        "entity_id": p.entity_id,
        "plan_type": p.plan_type,
        "plan_type_label": "收款" if p.plan_type == "receive" else "付款",
        "amount": round(p.amount or 0, 2),
        "plan_date": p.plan_date.strftime("%Y-%m-%d") if p.plan_date else "",
        "counterparty": p.counterparty or "",
        "description": p.description or "",
        "status": p.status,
        "status_label": {"pending": "待执行", "completed": "已完成", "cancelled": "已取消"}.get(p.status, p.status),
        "completed_at": p.completed_at.strftime("%Y-%m-%d %H:%M") if p.completed_at else None,
        "created_at": p.created_at.strftime("%Y-%m-%d %H:%M") if p.created_at else None,
    }


# ══════════════════════════════════════════════════════════
# 1. 资金缺口预测
# ══════════════════════════════════════════════════════════

@router.get("/gap-forecast")
def api_gap_forecast(
    entity_id: int = Query(1, description="企业ID"),
    days: int = Query(30, ge=1, le=90, description="预测天数"),
    current_cash: float = Query(None, description="当前现金余额(万元)，不传则自动获取"),
    db: Session = Depends(get_db),
):
    """资金缺口预测 — 趋势引擎 + 收付款计划，识别余额<警戒线的缺口日期"""
    try:
        return forecast_cash_flow_with_plans(entity_id, db, days=days, current_cash=current_cash)
    except Exception as e:
        logger.error(f"资金缺口预测失败: {e}", exc_info=True)
        raise HTTPException(400, f"资金缺口预测失败: {str(e)}")


@router.get("/balance")
def api_get_balance(
    entity_id: int = Query(1),
    db: Session = Depends(get_db),
):
    """获取当前现金余额（预测基线）"""
    from app.utils.cash_forecast_engine import get_current_cash_balance
    value = get_current_cash_balance(db, entity_id)
    return {"entity_id": entity_id, "current_cash": value}


@router.post("/balance")
def api_set_balance(
    data: dict,
    db: Session = Depends(get_db),
):
    """设置当前现金余额（万元），作为预测基线"""
    from app.utils.cash_forecast_engine import set_current_cash_balance
    value = float(data.get("current_cash", 0))
    if value < 0:
        raise HTTPException(400, "现金余额不能为负")
    set_current_cash_balance(db, value)
    return {"message": "当前现金余额已更新", "current_cash": value}


# ══════════════════════════════════════════════════════════
# 2. 收付款计划 CRUD
# ══════════════════════════════════════════════════════════

@router.get("/plans")
def api_list_plans(
    entity_id: int = Query(1),
    plan_type: str = Query(None, description="receive/pay"),
    status: str = Query(None, description="pending/completed/cancelled"),
    month: str = Query(None, description="YYYY-MM 按计划月份过滤"),
    page: int = Query(1, ge=1),
    page_size: int = Query(100, ge=1, le=500),
    db: Session = Depends(get_db),
):
    """收付款计划列表"""
    query = db.query(CashPlan).filter(CashPlan.entity_id == entity_id)
    if plan_type:
        query = query.filter(CashPlan.plan_type == plan_type)
    if status:
        query = query.filter(CashPlan.status == status)
    if month:
        try:
            y, m = int(month[:4]), int(month[5:7])
            start = datetime(y, m, 1)
            end = (start + timedelta(days=32)).replace(day=1)
            query = query.filter(CashPlan.plan_date >= start, CashPlan.plan_date < end)
        except Exception:
            raise HTTPException(400, "month格式应为YYYY-MM")
    total = query.count()
    plans = query.order_by(CashPlan.plan_date.asc(), CashPlan.id.desc()) \
        .offset((page - 1) * page_size).limit(page_size).all()
    return {"total": total, "data": [_plan_dict(p) for p in plans]}


@router.post("/plans")
def api_create_plan(data: dict, db: Session = Depends(get_db)):
    """新建收付款计划"""
    plan_type = data.get("plan_type")
    if plan_type not in ("receive", "pay"):
        raise HTTPException(400, "plan_type必须为receive(收)或pay(付)")
    amount = float(data.get("amount", 0))
    if amount <= 0:
        raise HTTPException(400, "金额必须大于0")
    date_str = data.get("plan_date")
    if not date_str:
        raise HTTPException(400, "缺少计划日期")
    try:
        plan_date = datetime.strptime(str(date_str)[:10], "%Y-%m-%d")
    except Exception:
        raise HTTPException(400, "plan_date格式应为YYYY-MM-DD")

    plan = CashPlan(
        entity_id=int(data.get("entity_id", 1)),
        plan_type=plan_type,
        amount=amount,
        plan_date=plan_date,
        counterparty=(data.get("counterparty") or "").strip(),
        description=(data.get("description") or "").strip(),
        status=data.get("status", "pending"),
    )
    db.add(plan)
    db.commit()
    db.refresh(plan)
    logger.info(f"新建收付款计划 #{plan.id} [{plan_type}] {amount}万 {date_str}")
    return {"message": "收付款计划已创建", "data": _plan_dict(plan)}


@router.put("/plans/{plan_id}")
def api_update_plan(plan_id: int, data: dict, db: Session = Depends(get_db)):
    """更新收付款计划"""
    plan = db.query(CashPlan).filter(CashPlan.id == plan_id).first()
    if not plan:
        raise HTTPException(404, "计划不存在")
    if "plan_type" in data:
        if data["plan_type"] not in ("receive", "pay"):
            raise HTTPException(400, "plan_type必须为receive或pay")
        plan.plan_type = data["plan_type"]
    if "amount" in data:
        amount = float(data["amount"])
        if amount <= 0:
            raise HTTPException(400, "金额必须大于0")
        plan.amount = amount
    if "plan_date" in data and data["plan_date"]:
        try:
            plan.plan_date = datetime.strptime(str(data["plan_date"])[:10], "%Y-%m-%d")
        except Exception:
            raise HTTPException(400, "plan_date格式应为YYYY-MM-DD")
    if "counterparty" in data:
        plan.counterparty = (data["counterparty"] or "").strip()
    if "description" in data:
        plan.description = (data["description"] or "").strip()
    if "status" in data:
        plan.status = data["status"]
        if data["status"] == "completed" and not plan.completed_at:
            plan.completed_at = datetime.now()
        elif data["status"] in ("pending", "cancelled"):
            plan.completed_at = None
    db.commit()
    db.refresh(plan)
    return {"message": "计划已更新", "data": _plan_dict(plan)}


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


@router.post("/plans/{plan_id}/complete")
def api_complete_plan(plan_id: int, db: Session = Depends(get_db)):
    """标记计划为已完成（收款到账/付款完成）"""
    plan = db.query(CashPlan).filter(CashPlan.id == plan_id).first()
    if not plan:
        raise HTTPException(404, "计划不存在")
    plan.status = "completed"
    plan.completed_at = datetime.now()
    db.commit()
    db.refresh(plan)
    return {"message": "已标记完成", "data": _plan_dict(plan)}


# ══════════════════════════════════════════════════════════
# 3. 到期提醒 + 页面看板
# ══════════════════════════════════════════════════════════

@router.get("/upcoming")
def api_upcoming(
    entity_id: int = Query(1),
    days: int = Query(7, ge=1, le=30),
    db: Session = Depends(get_db),
):
    """未来N天到期提醒 + 已逾期未收/未付"""
    today = datetime.now().replace(hour=0, minute=0, second=0, microsecond=0)
    upcoming = db.query(CashPlan).filter(
        CashPlan.entity_id == entity_id,
        CashPlan.status == "pending",
        CashPlan.plan_date >= today,
        CashPlan.plan_date <= today + timedelta(days=days),
    ).order_by(CashPlan.plan_date.asc()).all()
    overdue = db.query(CashPlan).filter(
        CashPlan.entity_id == entity_id,
        CashPlan.status == "pending",
        CashPlan.plan_date < today,
    ).order_by(CashPlan.plan_date.asc()).all()
    return {
        "days": days,
        "upcoming": [_plan_dict(p) for p in upcoming],
        "overdue": [_plan_dict(p) for p in overdue],
        "overdue_receive_amount": round(sum(p.amount for p in overdue if p.plan_type == "receive"), 2),
        "overdue_pay_amount": round(sum(p.amount for p in overdue if p.plan_type == "pay"), 2),
    }


@router.get("/dashboard")
def api_cash_dashboard(
    entity_id: int = Query(1),
    month: str = Query(None, description="YYYY-MM 默认本月"),
    days: int = Query(30),
    current_cash: float = Query(None, description="当前现金余额(万元)"),
    db: Session = Depends(get_db),
):
    """收付款计划页面看板 — 日历汇总 + 预测 + 到期提醒"""
    today = datetime.now()
    if month:
        try:
            y, m = int(month[:4]), int(month[5:7])
        except Exception:
            raise HTTPException(400, "month格式应为YYYY-MM")
    else:
        y, m = today.year, today.month
    start = datetime(y, m, 1)
    end = (start + timedelta(days=32)).replace(day=1)

    plans = db.query(CashPlan).filter(
        CashPlan.entity_id == entity_id,
        CashPlan.status == "pending",
        CashPlan.plan_date >= start,
        CashPlan.plan_date < end,
    ).all()

    # 日历：按天汇总 应收/应付
    calendar = {}
    for p in plans:
        dkey = p.plan_date.strftime("%Y-%m-%d")
        cell = calendar.setdefault(dkey, {"receive": 0.0, "pay": 0.0, "items": []})
        if p.plan_type == "receive":
            cell["receive"] += p.amount
        else:
            cell["pay"] += p.amount
        cell["items"].append(_plan_dict(p))

    # 本月合计
    month_receive = round(sum(p.amount for p in plans if p.plan_type == "receive"), 2)
    month_pay = round(sum(p.amount for p in plans if p.plan_type == "pay"), 2)

    forecast = forecast_cash_flow_with_plans(entity_id, db, days=days, current_cash=current_cash)
    upcoming = api_upcoming(entity_id, 7, db)

    return {
        "entity_id": entity_id,
        "month": f"{y:04d}-{m:02d}",
        "month_receive": month_receive,
        "month_pay": month_pay,
        "month_net": round(month_receive - month_pay, 2),
        "calendar": calendar,
        "forecast": forecast,
        "upcoming": upcoming,
    }


# ══════════════════════════════════════════════════════════
# 4. 资金预警 — 缺口前3天预警 + 到期未收款提醒
# ══════════════════════════════════════════════════════════

@router.post("/check-alerts")
def api_check_cash_alerts(entity_id: int = 1, db: Session = Depends(get_db)):
    """手动触发资金预警检查（写入预警中心kpi_alerts）"""
    try:
        return check_cash_alerts(db, entity_id=entity_id)
    except Exception as e:
        logger.error(f"资金预警检查失败: {e}", exc_info=True)
        raise HTTPException(400, f"资金预警检查失败: {str(e)}")


@router.get("/alerts/status")
def api_cash_alert_status(entity_id: int = Query(1), db: Session = Depends(get_db)):
    """资金预警状态概览 — 当前缺口/逾期情况（不写库，只读）"""
    result = forecast_cash_flow_with_plans(entity_id, db, days=30)
    return {
        "entity_id": entity_id,
        "warning_line": result["warning_line"],
        "critical_line": result["critical_line"],
        "gap_dates": result["gap_dates"],
        "pre_alerts": result["pre_alerts"],
        "min_cash": result["min_cash"],
        "min_cash_date": result["min_cash_date"],
        "summary": result["summary"],
    }
