"""数据分类分级 — 重要数据标记（2026-08-26 政策驱动）

背景：《网络数据安全风险评估办法》（2026-08-20 三部门施行）
- 重要数据处理者每年一次强制评估
- 评估前提 = 先分类分级（"不知道重要数据在哪，评估无从谈起"）
- 本模块 = "分类分级工具"第一版（标记+清单），不做评估算法

数据级别（参考 GB/T 43697 简化）：
- core 核心数据（一旦遭篡改/破坏/泄露，直接危害国家安全/经济运行）
- important 重要数据（一旦遭篡改/破坏/泄露，危害公共利益/企业关键业务）
- general 一般数据（其余）

覆盖对象：
- subjects 会计科目（全局，无 entity_id，与现有科目管理一致）
- kpi_definitions KPI字典（按 entity_id 多租户隔离）
"""
from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.orm import Session
from sqlalchemy import func, or_
from typing import Optional, List
from datetime import datetime
import csv
import io

from app.database import get_db
from app.deps import get_entity_id
from app.auth_middleware import require_role, require_auth
from app.models import Subject, KPIDefinition, Entity

router = APIRouter(prefix="/api/cma/data-classification", tags=["数据分类分级"],
    dependencies=[Depends(require_role("ceo", "finance", "business", "it"))],
)

# 写操作只允许 ceo/finance/it（与 KPI 字典一致）
WRITE_ROLES = Depends(require_role("ceo", "finance", "it"))

VALID_LEVELS = {"core", "important", "general"}

LEVEL_LABELS = {
    "core": "核心数据",
    "important": "重要数据",
    "general": "一般数据",
}

# 行业参考目录（内置提示，可按行业自定义扩展）
INDUSTRY_REFERENCE = [
    {"industry": "通用/企业服务", "category": "客户数据", "suggest_level": "important",
     "desc": "客户名单、合同、订单、应收账款等客户经营数据"},
    {"industry": "通用/企业服务", "category": "财务数据", "suggest_level": "important",
     "desc": "财务报表、银行账户、税务申报、薪酬数据"},
    {"industry": "通用/企业服务", "category": "员工数据", "suggest_level": "important",
     "desc": "员工身份、薪酬、社保、考勤、健康信息"},
    {"industry": "金融", "category": "账户交易", "suggest_level": "core",
     "desc": "客户账户、交易流水、信贷记录（金融行业核心数据）"},
    {"industry": "医疗", "category": "健康医疗", "suggest_level": "core",
     "desc": "病历、健康档案、基因数据（医疗行业核心数据）"},
    {"industry": "工业", "category": "关键基础设施", "suggest_level": "important",
     "desc": "生产控制、工艺参数、供应链关键环节数据"},
    {"industry": "互联网", "category": "用户个人信息", "suggest_level": "important",
     "desc": "个人信息、日志、位置数据（万人以上规模需重点评估）"},
    {"industry": "能源", "category": "能源数据", "suggest_level": "important",
     "desc": "能源生产、传输、消费监测数据"},
]


def _subject_to_item(s: Subject) -> dict:
    return {
        "type": "subject",
        "id": s.id,
        "code": s.subject_code,
        "name": s.subject_name,
        "dimension": None,
        "category": s.new_standard_category or s.category or "",
        "important_flag": 1 if s.important_flag else 0,
        "data_level": s.data_level or "general",
        "data_category": s.data_category or "",
        "data_owner": None,
        "storage": "会计科目台账",
    }


def _kpi_to_item(k: KPIDefinition) -> dict:
    return {
        "type": "kpi",
        "id": k.id,
        "code": k.kpi_code,
        "name": k.kpi_name,
        "dimension": k.dimension,
        "category": k.category or "",
        "important_flag": 1 if k.important_flag else 0,
        "data_level": k.data_level or "general",
        "data_category": k.data_category or "",
        "data_owner": k.data_owner,
        "storage": f"KPI台账(entity_id={k.entity_id})",
    }


def _query_items(
    data_type: Optional[str],
    data_level: Optional[str],
    important: Optional[int],
    keyword: Optional[str],
    entity_id: int,
    db: Session,
) -> list:
    """内部清单查询（供 inventory/export 复用，避免依赖注入问题）"""
    items: list[dict] = []

    if not data_type or data_type == "subject":
        q = db.query(Subject).filter(Subject.is_active == 1)
        if data_level:
            q = q.filter(Subject.data_level == data_level)
        if important == 1:
            q = q.filter(Subject.important_flag == 1)
        if keyword:
            like = f"%{keyword}%"
            q = q.filter(
                Subject.subject_name.like(like) | Subject.subject_code.like(like)
            )
        for s in q.order_by(Subject.subject_code).all():
            items.append(_subject_to_item(s))

    if not data_type or data_type == "kpi":
        q = db.query(KPIDefinition).filter(
            KPIDefinition.status == "active",
            KPIDefinition.entity_id == entity_id,
        )
        if data_level:
            q = q.filter(KPIDefinition.data_level == data_level)
        if important == 1:
            q = q.filter(KPIDefinition.important_flag == 1)
        if keyword:
            like = f"%{keyword}%"
            q = q.filter(
                KPIDefinition.kpi_name.like(like) | KPIDefinition.kpi_code.like(like)
            )
        for k in q.order_by(KPIDefinition.kpi_code).all():
            items.append(_kpi_to_item(k))

    return items


def _stats_of(items: list) -> dict:
    return {
        "total": len(items),
        "marked": sum(1 for i in items if i["important_flag"] == 1),
        "by_level": {
            "core": sum(1 for i in items if i["data_level"] == "core"),
            "important": sum(1 for i in items if i["data_level"] == "important"),
            "general": sum(1 for i in items if i["data_level"] == "general"),
        },
        "by_type": {
            "subject": sum(1 for i in items if i["type"] == "subject"),
            "kpi": sum(1 for i in items if i["type"] == "kpi"),
        },
    }


@router.get("/inventory")
def get_inventory(
    data_type: Optional[str] = Query(None, description="subject/kpi，缺省返回全部"),
    data_level: Optional[str] = Query(None, description="core/important/general 过滤"),
    important: Optional[int] = Query(None, description="1=仅已标记重要数据"),
    keyword: Optional[str] = Query(None, description="编码/名称搜索"),
    entity_id: int = Depends(get_entity_id),
    db: Session = Depends(get_db),
    current_user = Depends(require_auth),
):
    """数据资产清单（科目 + KPI 合并输出，含重要级别）"""
    if data_level and data_level not in VALID_LEVELS:
        raise HTTPException(400, f"无效的数据级别: {data_level}，可选 {sorted(VALID_LEVELS)}")

    items = _query_items(data_type, data_level, important, keyword, entity_id, db)
    return {"total": len(items), "items": items, "stats": _stats_of(items)}


@router.get("/stats")
def get_stats(
    entity_id: int = Depends(get_entity_id),
    db: Session = Depends(get_db),
    current_user = Depends(require_auth),
):
    """数据分类分级统计概览（评估前准备看板）"""
    subject_total = db.query(Subject).filter(Subject.is_active == 1).count()
    subject_marked = db.query(Subject).filter(
        Subject.is_active == 1, Subject.important_flag == 1
    ).count()
    kpi_total = db.query(KPIDefinition).filter(
        KPIDefinition.status == "active", KPIDefinition.entity_id == entity_id
    ).count()
    kpi_marked = db.query(KPIDefinition).filter(
        KPIDefinition.status == "active",
        KPIDefinition.entity_id == entity_id,
        KPIDefinition.important_flag == 1,
    ).count()

    ent = db.query(Entity).filter(Entity.id == entity_id).first()
    return {
        "entity_id": entity_id,
        "entity_name": ent.name if ent else "",
        "subjects": {"total": subject_total, "marked": subject_marked},
        "kpis": {"total": kpi_total, "marked": kpi_marked},
        "total": subject_total + kpi_total,
        "marked_total": subject_marked + kpi_marked,
        "coverage_pct": round((subject_marked + kpi_marked) / (subject_total + kpi_total) * 100, 1)
        if (subject_total + kpi_total) else 0,
        "policy_note": "《网络数据安全风险评估办法》(2026-08-20施行)：重要数据处理者每年一次强制评估，评估前提=先完成数据分类分级",
    }


@router.put("/subjects/{subject_id}")
def mark_subject(
    subject_id: int,
    important_flag: Optional[int] = Query(None, description="1=重要数据, 0=取消"),
    data_level: Optional[str] = Query(None, description="core/important/general"),
    data_category: Optional[str] = Query(None, description="行业参考分类(自定义)"),
    db: Session = Depends(get_db),
    current_user = Depends(require_auth),
):
    """标记单个科目：重要数据标记 + 数据分级 + 行业分类"""
    subject = db.query(Subject).filter(Subject.id == subject_id).first()
    if not subject:
        raise HTTPException(404, "科目不存在")

    if data_level is not None and data_level not in VALID_LEVELS:
        raise HTTPException(400, f"无效的数据级别: {data_level}，可选 {sorted(VALID_LEVELS)}")

    if important_flag is not None:
        subject.important_flag = 1 if important_flag else 0
    if data_level is not None:
        subject.data_level = data_level
        if data_level in ("core", "important"):
            subject.important_flag = 1  # 核心/重要级别自动视为重要数据
    if data_category is not None:
        subject.data_category = data_category or None
    db.commit()

    return {
        "message": "更新成功",
        "subject_id": subject_id,
        "important_flag": subject.important_flag,
        "data_level": subject.data_level,
        "data_category": subject.data_category,
    }


@router.put("/kpis/{kpi_id}")
def mark_kpi(
    kpi_id: int,
    important_flag: Optional[int] = Query(None, description="1=重要数据, 0=取消"),
    data_level: Optional[str] = Query(None, description="core/important/general"),
    data_category: Optional[str] = Query(None, description="行业参考分类(自定义)"),
    entity_id: int = Depends(get_entity_id),
    db: Session = Depends(get_db),
    current_user = Depends(require_auth),
):
    """标记单个KPI：重要数据标记 + 数据分级 + 行业分类（按账套隔离）"""
    kpi = db.query(KPIDefinition).filter(
        KPIDefinition.id == kpi_id,
        KPIDefinition.entity_id == entity_id,
    ).first()
    if not kpi:
        raise HTTPException(404, "KPI不存在或不属于当前账套")

    if data_level is not None and data_level not in VALID_LEVELS:
        raise HTTPException(400, f"无效的数据级别: {data_level}，可选 {sorted(VALID_LEVELS)}")

    if important_flag is not None:
        kpi.important_flag = 1 if important_flag else 0
    if data_level is not None:
        kpi.data_level = data_level
        if data_level in ("core", "important"):
            kpi.important_flag = 1  # 核心/重要级别自动视为重要数据
    if data_category is not None:
        kpi.data_category = data_category or None
    db.commit()

    return {
        "message": "更新成功",
        "kpi_id": kpi_id,
        "important_flag": kpi.important_flag,
        "data_level": kpi.data_level,
        "data_category": kpi.data_category,
    }


@router.put("/batch")
def batch_mark(
    data_type: str = Query(..., description="subject/kpi"),
    ids: List[int] = Query(..., description="ID列表"),
    important_flag: Optional[int] = Query(None, description="1=重要数据, 0=取消"),
    data_level: Optional[str] = Query(None, description="core/important/general"),
    data_category: Optional[str] = Query(None, description="行业参考分类(自定义)"),
    entity_id: int = Depends(get_entity_id),
    db: Session = Depends(get_db),
    current_user = Depends(require_auth),
):
    """批量标记（科目全局 / KPI按账套隔离）"""
    if data_type not in ("subject", "kpi"):
        raise HTTPException(400, f"无效的数据类型: {data_type}，可选 subject/kpi")
    if data_level is not None and data_level not in VALID_LEVELS:
        raise HTTPException(400, f"无效的数据级别: {data_level}，可选 {sorted(VALID_LEVELS)}")
    if not ids:
        raise HTTPException(400, "ids 不能为空")

    updated = 0
    if data_type == "subject":
        q = db.query(Subject).filter(Subject.id.in_(ids), Subject.is_active == 1)
        targets = q.all()
        for s in targets:
            if important_flag is not None:
                s.important_flag = 1 if important_flag else 0
            if data_level is not None:
                s.data_level = data_level
                if data_level in ("core", "important"):
                    s.important_flag = 1
            if data_category is not None:
                s.data_category = data_category or None
            updated += 1
    else:
        q = db.query(KPIDefinition).filter(
            KPIDefinition.id.in_(ids),
            KPIDefinition.entity_id == entity_id,
            KPIDefinition.status == "active",
        )
        targets = q.all()
        for k in targets:
            if important_flag is not None:
                k.important_flag = 1 if important_flag else 0
            if data_level is not None:
                k.data_level = data_level
                if data_level in ("core", "important"):
                    k.important_flag = 1
            if data_category is not None:
                k.data_category = data_category or None
            updated += 1

    db.commit()
    return {"message": f"批量更新成功", "data_type": data_type, "updated_count": updated}


@router.get("/export")
def export_csv(
    data_type: Optional[str] = Query(None, description="subject/kpi，缺省全部"),
    data_level: Optional[str] = Query(None, description="core/important/general 过滤"),
    important: Optional[int] = Query(None, description="1=仅已标记重要数据"),
    entity_id: int = Depends(get_entity_id),
    db: Session = Depends(get_db),
    current_user = Depends(require_auth),
):
    """导出数据分类分级清单（评估前准备材料）CSV"""
    if data_level and data_level not in VALID_LEVELS:
        raise HTTPException(400, f"无效的数据级别: {data_level}")

    items = _query_items(data_type, data_level, important, None, entity_id, db)

    buf = io.StringIO()
    writer = csv.writer(buf)
    writer.writerow(["类型", "编码", "名称", "维度", "分类", "重要标记", "数据级别", "行业参考分类", "数据责任人", "存储位置"])
    for i in items:
        writer.writerow([
            "科目" if i["type"] == "subject" else "KPI",
            i["code"],
            i["name"],
            i["dimension"] or "",
            i["category"] or "",
            "是" if i["important_flag"] else "否",
            LEVEL_LABELS.get(i["data_level"], i["data_level"]),
            i["data_category"] or "",
            i["data_owner"] or "",
            i["storage"] or "",
        ])

    content = "\ufeff" + buf.getvalue()  # BOM 兼容 Excel
    filename = f"data-classification-inventory_{datetime.now().strftime('%Y%m%d')}.csv"
    from starlette.responses import Response
    return Response(
        content=content,
        media_type="text/csv; charset=utf-8",
        headers={"Content-Disposition": f'attachment; filename="{filename}"'},
    )


@router.get("/industry-reference")
def industry_reference():
    """行业参考目录（内置提示，按行业给出重点数据分类建议）"""
    return {"items": INDUSTRY_REFERENCE}
