from fastapi import APIRouter, Depends, Query, Request
from ...core.database import get_db, get_runtime_db
from ...core.permission import get_current_user, is_admin_role
from ...core.config import settings
import httpx
import json
from datetime import date, datetime, timedelta
from ...utils.request_utils import safe_json

router = APIRouter()

GRAPHITI_SERVER_URL = getattr(settings, "GRAPHITI_BASE_URL", "http://localhost:2082")
def _check_admin(request: Request):
    current_user = get_current_user(request)
    if not current_user or not is_admin_role(current_user["role"]):
        return None, {"error": "无权限", "detail": "admin required"}
    return current_user, None


@router.get("/dashboard")
async def knowledge_dashboard(request: Request, db=Depends(get_db)):
    """知识库总览仪表盘 - 三通道数据汇总"""
    _, err = _check_admin(request)
    if err:
        return err

    conn, cur = db
    result = {
        "wiki": {},
        "graph": {},
        "timeliness": {},
        "health_score": 0,
    }

    try:
        # Wiki 统计
        await cur.execute("SELECT COUNT(*) as total FROM wiki_pages")
        wiki_total = (await cur.fetchone())["total"]
        await cur.execute("SELECT COUNT(*) as published FROM wiki_pages WHERE is_published = 1")
        wiki_published = (await cur.fetchone())["published"]
        await cur.execute("SELECT COUNT(*) as pending FROM wiki_pages WHERE review_status = 'pending_review'")
        wiki_pending = (await cur.fetchone())["pending"]

        result["wiki"] = {
            "total_pages": wiki_total,
            "published_pages": wiki_published,
            "pending_review": wiki_pending,
            "published_rate": round(wiki_published / wiki_total * 100, 1) if wiki_total > 0 else 0,
        }

        # Graphiti 统计
        try:
            async with httpx.AsyncClient(timeout=10) as client:
                res = await client.get(f"{GRAPHITI_SERVER_URL}/api/knowledge-graph/stats")
                if res.status_code == 200:
                    stats = res.json()
                    result["graph"] = {
                        "node_count": stats.get("node_count", 0),
                        "edge_count": stats.get("edge_count", 0),
                        "connected": True,
                    }
                else:
                    result["graph"] = {"connected": False, "error": f"HTTP {res.status_code}"}
        except Exception as e:
            result["graph"] = {"connected": False, "error": str(e)}

        # 时效性提醒
        today = date.today()
        await cur.execute(
            """SELECT COUNT(*) as expiring FROM wiki_pages
               WHERE compile_status = 'compiled'
               AND metadata IS NOT NULL
               AND JSON_EXTRACT(metadata, '$.expiry_date') IS NOT NULL
               AND JSON_UNQUOTE(JSON_EXTRACT(metadata, '$.expiry_date')) != ''
               AND STR_TO_DATE(JSON_UNQUOTE(JSON_EXTRACT(metadata, '$.expiry_date')), '%%Y-%%m-%%d') BETWEEN %s AND DATE_ADD(%s, INTERVAL 90 DAY)""",
            (today, today),
        )
        expiring_count = (await cur.fetchone())["expiring"]

        await cur.execute(
            """SELECT COUNT(*) as expired FROM wiki_pages
               WHERE metadata IS NOT NULL
               AND JSON_EXTRACT(metadata, '$.expiry_date') IS NOT NULL
               AND JSON_UNQUOTE(JSON_EXTRACT(metadata, '$.expiry_date')) != ''
               AND STR_TO_DATE(JSON_UNQUOTE(JSON_EXTRACT(metadata, '$.expiry_date')), '%%Y-%%m-%%d') < %s""",
            (today,),
        )
        expired_count = (await cur.fetchone())["expired"]

        result["timeliness"] = {
            "expiring_soon_90d": expiring_count,
            "expired": expired_count,
        }

        # 综合健康评分 (0-100)
        health_score = 100
        if wiki_total > 0:
            health_score -= min((wiki_total - wiki_published) / wiki_total * 10, 10)
        if expired_count > 0:
            health_score -= min(expired_count * 2, 20)
        if not result["graph"].get("connected"):
            health_score -= 15
        result["health_score"] = max(round(health_score, 1), 0)

        return {"success": True, "data": result}
    except Exception as e:
        return {"error": f"获取仪表盘数据失败: {str(e)}"}


@router.get("/timeliness")
async def knowledge_timeliness(
    request: Request,
    page: int = Query(1, ge=1),
    pageSize: int = Query(20, ge=1, le=100),
    warning_level: str = Query(""),
    db=Depends(get_db),
):
    """时效性提醒列表 - 过期/即将到期法规"""
    _, err = _check_admin(request)
    if err:
        return err

    conn, cur = db
    try:
        where_clauses = ["metadata IS NOT NULL", "JSON_EXTRACT(metadata, '$.expiry_date') IS NOT NULL", "JSON_UNQUOTE(JSON_EXTRACT(metadata, '$.expiry_date')) != ''"]
        params = []

        if warning_level:
            if warning_level == "expired":
                where_clauses.append("STR_TO_DATE(JSON_UNQUOTE(JSON_EXTRACT(metadata, '$.expiry_date')), '%%Y-%%m-%%d') < CURDATE()")
            elif warning_level == "critical":
                where_clauses.append("STR_TO_DATE(JSON_UNQUOTE(JSON_EXTRACT(metadata, '$.expiry_date')), '%%Y-%%m-%%d') BETWEEN CURDATE() AND DATE_ADD(CURDATE(), INTERVAL 30 DAY)")
            elif warning_level == "warning":
                where_clauses.append("STR_TO_DATE(JSON_UNQUOTE(JSON_EXTRACT(metadata, '$.expiry_date')), '%%Y-%%m-%%d') BETWEEN DATE_ADD(CURDATE(), INTERVAL 31 DAY) AND DATE_ADD(CURDATE(), INTERVAL 90 DAY)")

        where_sql = " AND ".join(where_clauses)

        await cur.execute(f"SELECT COUNT(*) as total FROM wiki_pages WHERE {where_sql}", tuple(params))
        total = (await cur.fetchone())["total"]

        offset = (page - 1) * pageSize
        await cur.execute(
            f"""SELECT id, title, review_status, compile_status,
                       JSON_UNQUOTE(JSON_EXTRACT(metadata, '$.expiry_date')) as expiry_date,
                       JSON_UNQUOTE(JSON_EXTRACT(metadata, '$.effective_date')) as effective_date,
                       DATEDIFF(STR_TO_DATE(JSON_UNQUOTE(JSON_EXTRACT(metadata, '$.expiry_date')), '%%Y-%%m-%%d'), CURDATE()) as days_remaining
                FROM wiki_pages
                WHERE {where_sql}
                ORDER BY
                    CASE WHEN STR_TO_DATE(JSON_UNQUOTE(JSON_EXTRACT(metadata, '$.expiry_date')), '%%Y-%%m-%%d') < CURDATE() THEN 0 ELSE 1 END,
                    STR_TO_DATE(JSON_UNQUOTE(JSON_EXTRACT(metadata, '$.expiry_date')), '%%Y-%%m-%%d') ASC
                LIMIT %s OFFSET %s""",
            tuple(params + [pageSize, offset]),
        )
        rows = await cur.fetchall()

        items = []
        today = date.today()
        for row in rows:
            item = dict(row)
            days = item.get("days_remaining")
            if days is not None:
                if days < 0:
                    item["warning_level"] = "expired"
                elif days <= 30:
                    item["warning_level"] = "critical"
                elif days <= 90:
                    item["warning_level"] = "warning"
                else:
                    item["warning_level"] = "normal"
            item["effective_date"] = str(item["effective_date"]) if item.get("effective_date") else None
            item["expiry_date"] = str(item["expiry_date"]) if item.get("expiry_date") else None
            items.append(item)

        return {"success": True, "list": items, "total": total, "page": page, "pageSize": pageSize}
    except Exception as e:
        return {"error": f"获取时效性数据失败: {str(e)}"}


@router.get("/wiki/stats")
async def wiki_stats(request: Request, db=Depends(get_db)):
    """Wiki 统计看板"""
    _, err = _check_admin(request)
    if err:
        return err

    conn, cur = db
    try:
        # 按 directory_id 统计（关联 wiki_directories 获取分类名）
        await cur.execute(
            """SELECT COALESCE(d.name, '未分类') as category, COUNT(p.id) as cnt
               FROM wiki_pages p
               LEFT JOIN wiki_directories d ON p.directory_id = d.id
               GROUP BY p.directory_id, d.name ORDER BY cnt DESC"""
        )
        category_rows = await cur.fetchall()
        category_stats = [{"category": r["category"], "count": r["cnt"]} for r in category_rows]

        # 按 compile_status 统计
        await cur.execute(
            """SELECT COALESCE(compile_status, '未编译') as compile_status, COUNT(*) as cnt
               FROM wiki_pages GROUP BY compile_status ORDER BY cnt DESC"""
        )
        compile_rows = await cur.fetchall()
        compile_stats = [{"status": r["compile_status"], "count": r["cnt"]} for r in compile_rows]

        # 按 review_status 统计
        await cur.execute(
            """SELECT review_status, COUNT(*) as cnt
               FROM wiki_pages GROUP BY review_status"""
        )
        status_rows = await cur.fetchall()
        status_stats = {r["review_status"]: r["cnt"] for r in status_rows}

        # 最近 7 天更新数
        await cur.execute(
            """SELECT COUNT(*) as cnt FROM wiki_pages
               WHERE updated_at >= DATE_SUB(NOW(), INTERVAL 7 DAY)"""
        )
        recent_updates = (await cur.fetchone())["cnt"]

        return {
            "success": True,
            "data": {
                "category_distribution": category_stats,
                "compile_status_distribution": compile_stats,
                "status_distribution": status_stats,
                "recent_7d_updates": recent_updates,
            }
        }
    except Exception as e:
        return {"error": f"获取 Wiki 统计失败: {str(e)}"}


@router.get("/wiki/lint")
async def wiki_lint(request: Request, db=Depends(get_db)):
    """Wiki 健康检查报告"""
    _, err = _check_admin(request)
    if err:
        return err

    conn, cur = db
    try:
        issues = []

        # 孤立页检测：无入链的页面（简化：没有关联内容的页面）
        await cur.execute(
            """SELECT id, title, path, review_status, updated_at
               FROM wiki_pages
               WHERE (content IS NULL OR LENGTH(TRIM(content)) < 50)
               LIMIT 100"""
        )
        orphan_rows = await cur.fetchall()
        for row in orphan_rows:
            issues.append({
                "id": row["id"],
                "title": row["title"],
                "type": "orphan",
                "description": "内容为空或过少（<50字符）",
                "status": row["review_status"],
            })

        # 编译失败检测
        await cur.execute(
            """SELECT id, title, compile_status, compile_status as status
               FROM wiki_pages
               WHERE compile_status = 'failed'
               LIMIT 100"""
        )
        failed_rows = await cur.fetchall()
        for row in failed_rows:
            issues.append({
                "id": row["id"],
                "title": row["title"],
                "type": "compile_failed",
                "description": "编译失败",
                "status": row["compile_status"],
            })

        # 元数据缺失检测
        await cur.execute(
            """SELECT id, title, tags, metadata, compile_status
               FROM wiki_pages
               WHERE (tags IS NULL OR JSON_LENGTH(tags) = 0 OR metadata IS NULL OR JSON_LENGTH(metadata) = 0)
               LIMIT 100"""
        )
        missing_rows = await cur.fetchall()
        for row in missing_rows:
            r = dict(row)
            missing_fields = []
            if not r.get("tags") or (isinstance(r.get("tags"), str) and r["tags"] == '[]'):
                missing_fields.append("tags")
            if not r.get("metadata") or (isinstance(r.get("metadata"), str) and r["metadata"] == '{}'):
                missing_fields.append("metadata")
            if missing_fields:
                issues.append({
                    "id": r["id"],
                    "title": r["title"],
                    "type": "missing_metadata",
                    "description": f"缺失字段: {', '.join(missing_fields)}",
                    "status": r.get("compile_status", ""),
                })

        return {
            "success": True,
            "issues": issues,
            "summary": {
                "total_issues": len(issues),
                "orphan_count": len([i for i in issues if i["type"] == "orphan"]),
                "compile_failed_count": len([i for i in issues if i["type"] == "compile_failed"]),
                "missing_metadata_count": len([i for i in issues if i["type"] == "missing_metadata"]),
            }
        }
    except Exception as e:
        return {"error": f"健康检查失败: {str(e)}"}


@router.post("/wiki/pages/batch-publish")
async def batch_publish_wiki_pages(request: Request, db=Depends(get_db)):
    """批量发布/下线 Wiki 页面"""
    _, err = _check_admin(request)
    if err:
        return err

    conn, cur = db
    try:
        body = await safe_json(request)
        page_ids = body.get("page_ids", [])
        target_status = body.get("target_status", "published")

        if not page_ids:
            return {"error": "缺少页面ID列表"}

        if target_status not in ("published", "draft", "archived"):
            return {"error": f"无效状态: {target_status}"}

        is_published = 1 if target_status == "published" else 0
        placeholders = ",".join(["%s"] * len(page_ids))

        await cur.execute(
            f"""UPDATE wiki_pages
                SET review_status = %s, is_published = %s, updated_at = NOW()
                WHERE id IN ({placeholders})""",
            (target_status, is_published) + tuple(page_ids),
        )
        updated_count = cur.rowcount

        return {
            "success": True,
            "message": f"已更新 {updated_count} 个页面",
            "updated_count": updated_count,
            "target_status": target_status,
        }
    except Exception as e:
        return {"error": f"批量更新失败: {str(e)}"}


@router.get("/graph/health")
async def graph_health(request: Request, db=Depends(get_db)):
    """图谱健康度评分"""
    _, err = _check_admin(request)
    if err:
        return err

    try:
        async with httpx.AsyncClient(timeout=30) as client:
            # 基础统计
            stats_res = await client.get(f"{GRAPHITI_SERVER_URL}/api/knowledge-graph/stats")
            stats = stats_res.json() if stats_res.status_code == 200 else {}

            node_count = stats.get("node_count", 0)
            edge_count = stats.get("edge_count", 0)

            # 闭环率：Violation->Article->Penalty 闭环占比
            closure_query = """
                MATCH (v:Violation)-[:VIOLATES]->(a:Article)
                OPTIONAL MATCH (a)-[:PENALIZES]->(p:Penalty)
                RETURN count(DISTINCT v) as total_violations,
                       count(DISTINCT CASE WHEN p IS NOT NULL THEN v END) as closed_violations
            """
            closure_res = await client.post(
                f"{GRAPHITI_SERVER_URL}/api/knowledge-graph/query",
                json={"query": closure_query},
            )
            closure_rate = 0
            if closure_res.status_code == 200:
                closure_data = closure_res.json().get("result", [{}])[0]
                total_v = closure_data.get("total_violations", 0)
                closed_v = closure_data.get("closed_violations", 0)
                closure_rate = round(closed_v / total_v * 100, 1) if total_v > 0 else 0

            # 内容充实度：Article 含 content_summary 的比例
            richness_query = """
                MATCH (a:Article)
                RETURN count(a) as total,
                       count(CASE WHEN a.content_summary IS NOT NULL AND a.content_summary <> '' THEN a END) as with_summary
            """
            richness_res = await client.post(
                f"{GRAPHITI_SERVER_URL}/api/knowledge-graph/query",
                json={"query": richness_query},
            )
            richness_rate = 0
            if richness_res.status_code == 200:
                richness_data = richness_res.json().get("result", [{}])[0]
                total_a = richness_data.get("total", 0)
                with_sum = richness_data.get("with_summary", 0)
                richness_rate = round(with_sum / total_a * 100, 1) if total_a > 0 else 0

            # 孤立节点占比
            orphan_query = """
                MATCH (n)
                WHERE NOT ()-[]->(n) AND NOT (n)-[]->()
                RETURN count(n) as orphan_count
            """
            orphan_res = await client.post(
                f"{GRAPHITI_SERVER_URL}/api/knowledge-graph/query",
                json={"query": orphan_query},
            )
            orphan_rate = 0
            if orphan_res.status_code == 200:
                orphan_data = orphan_res.json().get("result", [{}])[0]
                orphan_count = orphan_data.get("orphan_count", 0)
                orphan_rate = round(orphan_count / node_count * 100, 1) if node_count > 0 else 0

            # 综合健康分
            health_score = 100
            health_score -= max(0, (100 - closure_rate) * 0.3)
            health_score -= max(0, (100 - richness_rate) * 0.3)
            health_score -= orphan_rate * 0.5
            health_score = max(round(health_score, 1), 0)

            return {
                "success": True,
                "health_score": health_score,
                "metrics": {
                    "closure_rate": closure_rate,
                    "richness_rate": richness_rate,
                    "orphan_rate": orphan_rate,
                    "node_count": node_count,
                    "edge_count": edge_count,
                }
            }
    except Exception as e:
        return {"error": f"获取图谱健康度失败: {str(e)}"}


@router.get("/graph/import-log")
async def graph_import_log(
    request: Request,
    limit: int = Query(10, ge=1, le=50),
):
    """最近导入日志（从 runtime.db 读取）"""
    _, err = _check_admin(request)
    if err:
        return err

    try:
        async for conn, cur in get_runtime_db():
            # 查询 knowledge_sync_logs 表（如果存在）
            await cur.execute(
                """SELECT id, sync_type, source_file, status,
                           new_nodes_count, updated_nodes_count, created_at
                    FROM knowledge_sync_logs
                    ORDER BY created_at DESC
                    LIMIT %s""",
                (limit,),
            )
            rows = await cur.fetchall()

            logs = []
            for row in rows:
                logs.append({
                    "id": row["id"],
                    "sync_type": row["sync_type"],
                    "source_file": row["source_file"],
                    "status": row["status"],
                    "new_nodes": row["new_nodes_count"],
                    "updated_nodes": row["updated_nodes_count"],
                    "created_at": str(row["created_at"]) if row["created_at"] else None,
                })

            return {"success": True, "logs": logs}
    except Exception as e:
        # 表可能不存在，返回空列表
        return {"success": True, "logs": [], "note": "knowledge_sync_logs 表可能不存在"}


@router.get("/config")
async def knowledge_config(request: Request, db=Depends(get_db)):
    """获取知识库配置（只读）"""
    _, err = _check_admin(request)
    if err:
        return err

    return {
        "success": True,
        "config": {
            "graphiti": {
                "base_url": GRAPHITI_SERVER_URL,
                "neo4j_uri": getattr(settings, "NEO4J_URI", "bolt://localhost:7687"),
            },
            "embedding": {
                "model": getattr(settings, "EMBEDDING_MODEL", "BAAI/bge-large-zh-v1.5"),
                "api_base": getattr(settings, "EMBEDDING_API_BASE", "https://api.siliconflow.cn/v1"),
            },
            "rerank": {
                "enabled": getattr(settings, "RERANK_ENABLED", "true") != "false",
                "model": getattr(settings, "RERANK_MODEL", "BAAI/bge-reranker-v2-m3"),
            },
        }
    }


@router.post("/init-feature-flags")
async def init_knowledge_feature_flags(request: Request, db=Depends(get_db)):
    """初始化知识库相关 Feature Flags"""
    _, err = _check_admin(request)
    if err:
        return err

    conn, cur = db
    flags = [
        ("kb.search.enabled", "知识库搜索总开关", "boolean", "true", "global"),
        ("kb.search.suggest", "搜索联想/自动补全", "boolean", "true", "global"),
        ("kb.search.hot", "热门搜索推荐", "boolean", "true", "global"),
        ("kb.search.history", "搜索历史记录", "boolean", "true", "global"),
        ("kb.detail.related", "详情页关联内容展示", "boolean", "true", "global"),
        ("kb.detail.context", "上下文法条导航", "boolean", "true", "global"),
        ("kb.detail.relation_chain", "关联关系文本链", "boolean", "false", "global"),
        ("kb.graph.enabled", "知识图谱功能", "boolean", "true", "global"),
    ]

    created = 0
    skipped = 0
    for key, name, flag_type, value, scope in flags:
        await cur.execute("SELECT id FROM feature_flags WHERE flag_key = %s", (key,))
        if await cur.fetchone():
            skipped += 1
            continue

        value_boolean = 1 if value.lower() == "true" else 0
        await cur.execute(
            """INSERT INTO feature_flags
               (flag_key, flag_name, description, flag_type, value_boolean, target_edition, created_by)
               VALUES (%s, %s, %s, %s, %s, %s, %s)""",
            (key, name, f"知识库功能开关: {name}", flag_type, value_boolean, scope, "system"),
        )
        created += 1

    return {
        "success": True,
        "message": f"初始化完成: 新建 {created} 个, 跳过 {skipped} 个",
        "created": created,
        "skipped": skipped,
    }
