"""战略地图 API"""
from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.orm import Session
from typing import Optional
from app.database import get_db
from app.auth_middleware import require_auth, require_role
from app.models import StrategicMap, OperationLog, MapObjective
import json

router = APIRouter(prefix="/api/cma/maps", tags=["战略地图"],
    dependencies=[Depends(require_role("ceo", "finance"))],
)

# ── 四维度模板 ──────────────────────────────
STRATEGIC_MAP_TEMPLATE = [
    {
        "key": "finance",
        "name": "财务层",
        "icon": "💰",
        "color": "#F56C6C",
        "objectives": [
            {"name": "营收目标", "kpis": ["F_REVENUE"]},
            {"name": "净利润率", "kpis": ["F_NET_PROFIT"]},
            {"name": "现金流", "kpis": ["F_OP_CFLOW"]},
        ],
    },
    {
        "key": "customer",
        "name": "客户层",
        "icon": "👥",
        "color": "#409EFF",
        "objectives": [
            {"name": "客户满意度", "kpis": ["C_SATISFACTION"]},
            {"name": "市场份额", "kpis": ["C_MARKET_SHARE"]},
            {"name": "客户保留率", "kpis": ["C_RETENTION_RATE"]},
        ],
    },
    {
        "key": "process",
        "name": "内部流程层",
        "icon": "⚙️",
        "color": "#67C23A",
        "objectives": [
            {"name": "运营效率", "kpis": ["P_DELIVERY"]},
            {"name": "质量合格率", "kpis": ["P_PASS_RATE"]},
        ],
    },
    {
        "key": "learning",
        "name": "学习成长层",
        "icon": "📚",
        "color": "#E6A23C",
        "objectives": [
            {"name": "关键岗位胜任度", "kpis": ["L_COMPETENCY"]},
            {"name": "培训完成率", "kpis": ["L_TRAINING"]},
        ],
    },
]

# ── CRUD ────────────────────────────────────

@router.get("")
def list_maps(db: Session = Depends(get_db)):
    maps = db.query(StrategicMap).order_by(StrategicMap.updated_at.desc()).all()
    return {"data": [m_to_dict(m, db) for m in maps]}

@router.post("")
def create_map(data: dict, db: Session = Depends(get_db)):
    m = StrategicMap(**data)
    db.add(m)
    db.commit()
    db.refresh(m)
    _sync_map_objectives(m, db)
    return m_to_dict(m, db)


@router.post("/create-with-template")
def create_map_with_template(data: dict, db: Session = Depends(get_db)):
    """一键创建带四维度模板的战略地图"""
    m = StrategicMap(
        title=data.get("title", "新建战略地图"),
        version=data.get("version", "v1.0"),
        status="draft",
        dimensions=STRATEGIC_MAP_TEMPLATE,
        canvas_data={"connections": []},
    )
    db.add(m)
    db.commit()
    db.refresh(m)
    _sync_map_objectives(m, db)
    return m_to_dict(m, db)


@router.put("/{map_id}")
def update_map(map_id: int, data: dict, db: Session = Depends(get_db)):
    m = db.query(StrategicMap).filter(StrategicMap.id == map_id).first()
    if not m:
        raise HTTPException(404, "战略地图不存在")

    old_status = m.status
    for k, v in data.items():
        if hasattr(m, k) and v is not None:
            setattr(m, k, v)

    db.commit()
    # 同步目标到map_objectives表
    _sync_map_objectives(m, db)

    # ├─ 版本管理: draft → published 时自动创建快照
    if old_status == "draft" and m.status == "published":
        _auto_snapshot(m, db)

    return m_to_dict(m, db)


# ── 删除地图 ─────────────────────────────────


@router.delete("/{map_id}")
def delete_map(map_id: int, db: Session = Depends(get_db)):
    """删除战略地图"""
    m = db.query(StrategicMap).filter(StrategicMap.id == map_id).first()
    if not m:
        raise HTTPException(404, "战略地图不存在")
    db.delete(m)
    db.commit()
    return {"message": "已删除"}


@router.post("/batch-delete")
def batch_delete_maps(data: dict, db: Session = Depends(get_db)):
    """批量删除战略地图"""
    ids = data.get("ids", [])
    if not ids:
        raise HTTPException(400, "请选择要删除的地图")
    deleted = 0
    for mid in ids:
        m = db.query(StrategicMap).filter(StrategicMap.id == mid).first()
        if m:
            db.delete(m)
            deleted += 1
    db.commit()
    return {"message": f"已删除 {deleted} 个地图", "deleted": deleted}


# ── 连线管理 ─────────────────────────────────

def _get_connections(m: StrategicMap) -> list:
    if not m.canvas_data:
        m.canvas_data = {"connections": []}
    if isinstance(m.canvas_data, str):
        try:
            m.canvas_data = json.loads(m.canvas_data)
        except:
            m.canvas_data = {"connections": []}
    if "connections" not in m.canvas_data:
        m.canvas_data["connections"] = []
    return m.canvas_data["connections"]


@router.post("/{map_id}/connections")
def add_connection(map_id: int, data: dict, db: Session = Depends(get_db)):
    """新增因果连线: {"from": "learning-0", "to": "process-0"}"""
    m = db.query(StrategicMap).filter(StrategicMap.id == map_id).first()
    if not m:
        raise HTTPException(404, "战略地图不存在")

    from_id = data.get("from", "")
    to_id = data.get("to", "")

    if not from_id or not to_id:
        raise HTTPException(400, "请提供 from 和 to")

    # 校验: 不能自连
    if from_id == to_id:
        raise HTTPException(400, "不能自身连线")

    # 校验: 维度不能相同 (但放开允许同层连线, 仅禁止自连)
    from_dim = from_id.rsplit("-", 1)[0]
    to_dim = to_id.rsplit("-", 1)[0]

    conns = _get_connections(m)

    # 校验: 不能重复
    for c in conns:
        if c.get("from") == from_id and c.get("to") == to_id:
            raise HTTPException(400, "已存在相同的连线")

    conns.append({"from": from_id, "to": to_id, "style": "solid"})
    m.canvas_data["connections"] = conns
    db.commit()
    return {"connections": conns}


@router.delete("/{map_id}/connections")
def delete_connection_by_key(map_id: int, data: dict, db: Session = Depends(get_db)):
    """根据 from/to 删除连线"""
    m = db.query(StrategicMap).filter(StrategicMap.id == map_id).first()
    if not m:
        raise HTTPException(404, "战略地图不存在")

    from_id = data.get("from", "")
    to_id = data.get("to", "")

    conns = _get_connections(m)
    new_conns = [c for c in conns if not (c.get("from") == from_id and c.get("to") == to_id)]

    if len(new_conns) == len(conns):
        raise HTTPException(404, "连线不存在")

    m.canvas_data["connections"] = new_conns
    db.commit()
    return {"connections": new_conns, "removed": {"from": from_id, "to": to_id}}


# ── 版本管理 ─────────────────────────────────

def _auto_snapshot(m: StrategicMap, db: Session):
    """发布时自动创建版本快照"""
    from app.models import StrategicMapVersion
    import re

    # 自动递增版本号: 找到最大次版本号
    existing = db.query(StrategicMapVersion).filter(
        StrategicMapVersion.map_id == m.id
    ).order_by(StrategicMapVersion.id.desc()).first()

    if existing:
        match = re.search(r"v(\d+)\.(\d+)", existing.version)
        if match:
            major = int(match.group(1))
            minor = int(match.group(2)) + 1
            new_ver = f"v{major}.{minor}"
        else:
            new_ver = "v1.0"
    else:
        new_ver = "v1.0"

    # 确保 JSON 序列化
    dims = m.dimensions
    canvas = m.canvas_data
    if isinstance(dims, str):
        try:
            dims = json.loads(dims)
        except:
            dims = []
    if isinstance(canvas, str):
        try:
            canvas = json.loads(canvas)
        except:
            canvas = {"connections": []}

    snapshot = StrategicMapVersion(
        map_id=m.id,
        version=new_ver,
        dimensions=dims,
        canvas_data=canvas,
        comment=f"发布 {new_ver}",
    )
    db.add(snapshot)
    db.commit()


# ── 工具函数 ─────────────────────────────────

def m_to_dict(m, db: Session = None):
    d = {c.name: getattr(m, c.name) for c in m.__table__.columns}
    if db:
        _merge_map_objectives(m, db)
        d["dimensions"] = m.dimensions
    return d


def _sync_map_objectives(m, db):
    """保存时：将dimensions JSON中的目标同步到map_objectives表"""
    db.query(MapObjective).filter(MapObjective.map_id == m.id).delete()
    dims = m.dimensions
    if isinstance(dims, str):
        dims = json.loads(dims)
    for dim in dims:
        for i, obj in enumerate(dim.get("objectives", [])):
            mo = MapObjective(
                map_id=m.id,
                dimension_key=dim.get("key", ""),
                name=obj.get("name", ""),
                description=obj.get("description", ""),
                icon=obj.get("icon", "target"),
                kpis=obj.get("kpis", []),
                sort_order=i,
            )
            db.add(mo)
    db.commit()


def _merge_map_objectives(m, db):
    """读取时：将map_objectives表的数据合并进dimensions JSON"""
    objs = db.query(MapObjective).filter(MapObjective.map_id == m.id).order_by(MapObjective.sort_order).all()
    if not objs:
        return
    dims = m.dimensions
    if isinstance(dims, str):
        dims = json.loads(dims)
    # 按dimension_key分组
    from collections import defaultdict
    grouped = defaultdict(list)
    for o in objs:
        grouped[o.dimension_key].append(o)
    for dim in dims:
        key = dim.get("key", "")
        if key in grouped:
            dim["objectives"] = [{"name": o.name, "description": o.description or "", "icon": o.icon or "target", "kpis": o.kpis or []} for o in grouped[key]]
    m.dimensions = dims


# ── 战略回顾会 聚合接口 ──────────────────────


@router.get("/{map_id}/review")
def get_map_review(map_id: int, db: Session = Depends(get_db)):
    """战略回顾会：返回目标状态、KPI值、改善行动"""
    from app.models import KPIDefinition, KPIValue, ActionPlan
    m = db.query(StrategicMap).filter(StrategicMap.id == map_id).first()
    if not m:
        raise HTTPException(404, "战略地图不存在")

    dims = m.dimensions
    if isinstance(dims, str):
        dims = json.loads(dims)

    # 收集所有KPI code
    all_kpi_codes = set()
    for dim in dims:
        for obj in dim.get("objectives", []):
            for code in obj.get("kpis", []):
                all_kpi_codes.add(code)

    # 查询KPI定义
    kpi_defs = db.query(KPIDefinition).filter(
        KPIDefinition.kpi_code.in_(all_kpi_codes) if all_kpi_codes else False
    ).all() if all_kpi_codes else []
    kpi_map = {k.kpi_code: k for k in kpi_defs}

    # 查询最新KPI实际值
    kpi_ids = [k.id for k in kpi_defs]
    latest_values = {}
    if kpi_ids:
        # 取每个KPI的最新一条
        for kid in kpi_ids:
            v = db.query(KPIValue).filter(
                KPIValue.kpi_id == kid
            ).order_by(KPIValue.calculated_at.desc()).first()
            if v:
                latest_values[kid] = {
                    "actual_value": v.actual_value,
                    "period": v.period,
                    "source_type": v.source_type,
                }

    # 查询改善行动（按KPI_id关联）
    action_plans_data = []
    if kpi_ids:
        plans = db.query(ActionPlan).filter(
            ActionPlan.kpi_id.in_(kpi_ids)
        ).order_by(ActionPlan.created_at.desc()).all()
        for p in plans:
            action_plans_data.append({
                "id": p.id,
                "kpi_id": p.kpi_id,
                "title": p.title,
                "assignee": p.assignee,
                "priority": p.priority,
                "due_date": p.due_date.isoformat() if p.due_date else None,
                "status": p.status,
                "progress": p.progress or 0,
                "created_at": p.created_at.isoformat() if p.created_at else None,
            })

    # 构建维度目标状态
    dim_results = []
    total_ok = 0
    total_warn = 0
    total_err = 0
    total_obj_count = 0
    focus_items = []

    for dim in dims:
        dim_key = dim.get("key", "")
        dim_name = dim.get("name", "")
        dim_icon = dim.get("icon", "")
        dim_color = dim.get("color", "")
        objectives = []
        for obj in dim.get("objectives", []):
            total_obj_count += 1
            obj_kpis = []
            worst_level = "green"
            for code in obj.get("kpis", []):
                kpi_def = kpi_map.get(code)
                if not kpi_def:
                    continue
                lv = latest_values.get(kpi_def.id, {})
                actual = lv.get("actual_value")
                target = kpi_def.target_value
                # 判断红黄绿灯
                level = "gray"
                if actual is not None and target:
                    ratio = actual / target
                    if ratio >= 0.9:
                        level = "green"
                    elif ratio >= 0.7:
                        level = "yellow"
                    else:
                        level = "red"
                else:
                    level = "gray"

                if level == "red":
                    worst_level = "red"
                elif level == "yellow" and worst_level != "red":
                    worst_level = "yellow"

                obj_kpis.append({
                    "kpi_id": kpi_def.id,
                    "kpi_code": code,
                    "kpi_name": kpi_def.kpi_name,
                    "target_value": target,
                    "actual_value": actual,
                    "unit": kpi_def.unit,
                    "level": level,
                })

            obj_item = {
                "name": obj.get("name", ""),
                "icon": obj.get("icon", ""),
                "kpis": obj_kpis,
                "level": worst_level,
                "has_data": len(obj_kpis) > 0,
            }
            objectives.append(obj_item)

            if worst_level == "green":
                total_ok += 1
            elif worst_level == "yellow":
                total_warn += 1
            elif worst_level == "red":
                total_err += 1

            # 红色和黄色归入需重点关注
            if worst_level in ("red", "yellow"):
                focus_items.append(obj_item)

        dim_results.append({
            "key": dim_key,
            "name": dim_name,
            "icon": dim_icon,
            "color": dim_color,
            "objectives": objectives,
        })

    # 排序：红色在前，黄色在后
    focus_items.sort(key=lambda x: (0 if x["level"] == "red" else 1, x["name"]))

    return {
        "map_id": m.id,
        "title": m.title,
        "version": m.version,
        "status": m.status,
        "dimensions": dim_results,
        "summary": {
            "total": total_obj_count,
            "green": total_ok,
            "yellow": total_warn,
            "red": total_err,
            "health_score": round(total_ok / total_obj_count * 100, 1) if total_obj_count > 0 else 0,
        },
        "focus_items": focus_items,
        "action_plans": action_plans_data,
    }

