"""实际值自动归集 API — 管理会计OS (P1-④ 2026-08-28)

取数映射管理(kpi_value_sources) + 手动触发采集 + 采集日志 + 覆盖率统计
采集器本体: scripts/kpi_value_collector.py（系统 crontab 每日 06:30）
"""
from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.orm import Session
from typing import Optional

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 KPIValueSource, KPIValueCollectLog, KPIDefinition, KPIValue

router = APIRouter(
    prefix="/api/cma/budget",
    tags=["实际值归集"],
    dependencies=[Depends(require_role("ceo", "finance", "it"))],
)


# ── 取数映射 CRUD ──────────────────────────────

@router.get("/value-sources")
def list_value_sources(
    kpi_id: Optional[int] = Query(None),
    status: Optional[str] = Query(None),
    db: Session = Depends(get_db),
    entity_id: int = Depends(get_entity_id),
):
    """取数映射列表（按 entity_id 隔离）"""
    query = db.query(KPIValueSource).filter(KPIValueSource.entity_id == entity_id)
    if kpi_id:
        query = query.filter(KPIValueSource.kpi_id == kpi_id)
    if status:
        query = query.filter(KPIValueSource.status == status)
    rows = query.order_by(KPIValueSource.id.desc()).all()

    kpi_ids = {r.kpi_id for r in rows}
    kpis = {k.id: k for k in db.query(KPIDefinition).filter(KPIDefinition.id.in_(kpi_ids)).all()} if kpi_ids else {}
    result = []
    for r in rows:
        kpi = kpis.get(r.kpi_id)
        result.append({
            "id": r.id,
            "entity_id": r.entity_id,
            "kpi_id": r.kpi_id,
            "kpi_code": kpi.kpi_code if kpi else "",
            "kpi_name": kpi.kpi_name if kpi else "",
            "source_table": r.source_table,
            "source_field": r.source_field,
            "aggregate": r.aggregate,
            "filter_rule": r.filter_rule,
            "period_field": r.period_field,
            "unit_conversion": r.unit_conversion,
            "status": r.status,
            "created_at": r.created_at.isoformat() if r.created_at else None,
        })
    return {"data": result, "total": len(result)}


@router.post("/value-sources")
def create_value_source(
    data: dict,
    db: Session = Depends(get_db),
    entity_id: int = Depends(get_entity_id),
    current_user=Depends(require_auth),
):
    """新建取数映射"""
    kpi_id = data.get("kpi_id")
    source_table = data.get("source_table")
    source_field = data.get("source_field")
    if not kpi_id or not source_table or not source_field:
        raise HTTPException(400, "缺少必要参数: kpi_id, source_table, source_field")

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

    existing = db.query(KPIValueSource).filter(
        KPIValueSource.entity_id == entity_id,
        KPIValueSource.kpi_id == kpi_id,
        KPIValueSource.source_table == source_table,
    ).first()
    if existing:
        raise HTTPException(400, f"该KPI({kpi_id})已存在 {source_table} 取数映射")

    row = KPIValueSource(
        entity_id=entity_id,
        kpi_id=kpi_id,
        source_table=source_table,
        source_field=source_field,
        aggregate=data.get("aggregate", "sum"),
        filter_rule=data.get("filter_rule"),
        period_field=data.get("period_field", "period"),
        unit_conversion=data.get("unit_conversion", 1),
        status=data.get("status", "active"),
    )
    db.add(row)
    db.commit()
    db.refresh(row)
    return {"message": "取数映射已创建", "id": row.id}


@router.put("/value-sources/{source_id}")
def update_value_source(
    source_id: int,
    data: dict,
    db: Session = Depends(get_db),
    entity_id: int = Depends(get_entity_id),
    current_user=Depends(require_auth),
):
    """更新取数映射"""
    row = db.query(KPIValueSource).filter(
        KPIValueSource.id == source_id,
        KPIValueSource.entity_id == entity_id,
    ).first()
    if not row:
        raise HTTPException(404, "映射不存在")
    for field in ("source_table", "source_field", "aggregate", "filter_rule",
                  "period_field", "unit_conversion", "status"):
        if field in data:
            setattr(row, field, data[field])
    db.commit()
    return {"message": "映射已更新", "id": row.id}


@router.delete("/value-sources/{source_id}")
def delete_value_source(
    source_id: int,
    db: Session = Depends(get_db),
    entity_id: int = Depends(get_entity_id),
    current_user=Depends(require_auth),
):
    """删除取数映射"""
    row = db.query(KPIValueSource).filter(
        KPIValueSource.id == source_id,
        KPIValueSource.entity_id == entity_id,
    ).first()
    if not row:
        raise HTTPException(404, "映射不存在")
    db.delete(row)
    db.commit()
    return {"message": "映射已删除"}


@router.post("/value-sources/test")
def test_value_source(
    data: dict,
    db: Session = Depends(get_db),
    entity_id: int = Depends(get_entity_id),
):
    """试跑单条映射返回预览值（不写库）"""
    from scripts.kpi_value_collector import collect_for_mapping

    mapping = KPIValueSource(
        entity_id=entity_id,
        kpi_id=data.get("kpi_id"),
        source_table=data.get("source_table"),
        source_field=data.get("source_field"),
        aggregate=data.get("aggregate", "sum"),
        filter_rule=data.get("filter_rule"),
        period_field=data.get("period_field", "period"),
        unit_conversion=data.get("unit_conversion", 1),
        status="active",
    )
    period = data.get("period") or _default_period()
    try:
        value, message = collect_for_mapping(db, mapping, period, write_kpi=False)
        return {"success": True, "period": period, "value": value, "message": message}
    except Exception as e:
        return {"success": False, "period": period, "value": None, "message": str(e)}


# ── 采集器触发 ──────────────────────────────

@router.post("/value-collect/run")
def run_value_collect(
    data: dict,
    db: Session = Depends(get_db),
    entity_id: int = Depends(get_entity_id),
    current_user=Depends(require_auth),
):
    """手动触发采集器（可选 period 参数，默认当月）"""
    from scripts.kpi_value_collector import run_collector

    period = data.get("period") or _default_period()
    kpi_id = data.get("kpi_id")  # 可选: 只采集单个KPI
    result = run_collector(db, entity_id=entity_id, period=period, kpi_id=kpi_id)
    result["period"] = period
    return result


# ── 采集日志 ──────────────────────────────

@router.get("/value-collect/logs")
def list_collect_logs(
    status: Optional[str] = Query(None),
    period: Optional[str] = Query(None),
    limit: int = Query(50, ge=1, le=200),
    db: Session = Depends(get_db),
    entity_id: int = Depends(get_entity_id),
):
    """采集日志（status过滤）"""
    query = db.query(KPIValueCollectLog).filter(KPIValueCollectLog.entity_id == entity_id)
    if status:
        query = query.filter(KPIValueCollectLog.status == status)
    if period:
        query = query.filter(KPIValueCollectLog.period == period)
    rows = query.order_by(KPIValueCollectLog.collected_at.desc()).limit(limit).all()

    kpi_ids = {r.kpi_id for r in rows}
    kpis = {k.id: k for k in db.query(KPIDefinition).filter(KPIDefinition.id.in_(kpi_ids)).all()} if kpi_ids else {}
    result = []
    for r in rows:
        kpi = kpis.get(r.kpi_id)
        result.append({
            "id": r.id,
            "kpi_id": r.kpi_id,
            "kpi_code": kpi.kpi_code if kpi else "",
            "kpi_name": kpi.kpi_name if kpi else "",
            "period": r.period,
            "source_table": r.source_table,
            "collected_value": r.collected_value,
            "status": r.status,
            "message": r.message,
            "collected_at": r.collected_at.isoformat() if r.collected_at else None,
        })
    return {"data": result, "total": len(result)}


# ── 覆盖率统计 ──────────────────────────────

@router.get("/value-sources/coverage")
def value_source_coverage(
    db: Session = Depends(get_db),
    entity_id: int = Depends(get_entity_id),
):
    """覆盖率统计：已配映射KPI数 / 总活跃KPI数 / 未配置清单"""
    total_kpis = db.query(KPIDefinition).filter(
        KPIDefinition.entity_id == entity_id,
        KPIDefinition.status == "active",
    ).count()

    mapped_rows = db.query(KPIValueSource).filter(
        KPIValueSource.entity_id == entity_id,
        KPIValueSource.status == "active",
    ).all()
    mapped_kpi_ids = {r.kpi_id for r in mapped_rows}

    all_kpis = db.query(KPIDefinition).filter(
        KPIDefinition.entity_id == entity_id,
        KPIDefinition.status == "active",
    ).all()
    unmapped = [{
        "kpi_id": k.id,
        "kpi_code": k.kpi_code,
        "kpi_name": k.kpi_name,
    } for k in all_kpis if k.id not in mapped_kpi_ids]

    coverage = round(len(mapped_kpi_ids) / total_kpis * 100, 1) if total_kpis else 0
    return {
        "mapped_count": len(mapped_kpi_ids),
        "total_kpis": total_kpis,
        "coverage_pct": coverage,
        "unmapped_count": len(unmapped),
        "unmapped": unmapped,
    }


def _default_period() -> str:
    from datetime import datetime
    return datetime.now().strftime("%Y-%m")
