"""认知数据库诊断 — 量化每张表每个字段的填充率

用于 Issue #82 Schema-Population 鸿沟分析。
"""

from __future__ import annotations

import json
import logging
from pathlib import Path

from .db_cog import CogDatabase

logger = logging.getLogger(__name__)


def run_diagnosis(db_cog: CogDatabase, collection: str | None = None) -> dict:
    """运行诊断，返回结构化报告

    返回:
        {
            "tables": {
                "facts": {"total": N, "fields": {"assertion": {"non_null": N, "rate": 0.xx}, ...}},
                ...
            },
            "summary": {"total_fields": N, "fully_populated": N, "dead_fields": N}
        }
    """
    conn = db_cog.conn
    report: dict = {"tables": {}, "summary": {}}

    table_defs = {
        "facts": {
            "filter_base": "status='active'",
            "fields": [
                "id", "session_id", "collection", "assertion", "category",
                "scope_files", "scope_modules", "scope_entities",
                "confidence", "decay_rate", "source", "status",
                "superseded_by", "invalidated_reason",
                "access_count", "last_accessed", "last_validated",
                "embedding", "context_json",
                "created_at", "updated_at",
            ],
            "json_fields": ["scope_files", "scope_modules", "scope_entities", "context_json"],
        },
        "mental_models": {
            "filter_base": "status='active'",
            "fields": [
                "id", "collection", "subject", "scope",
                "understanding_level", "components", "causal_chains",
                "known_gaps", "open_questions", "based_on_facts",
                "depends_on_models", "revision", "status",
                "created_at", "updated_at",
            ],
            "json_fields": [
                "components", "causal_chains", "known_gaps",
                "open_questions", "based_on_facts", "depends_on_models",
            ],
        },
        "tactics": {
            "filter_base": "status='active'",
            "fields": [
                "id", "collection", "trigger_pattern", "trigger_keywords",
                "steps", "times_used", "times_succeeded", "success_rate",
                "specificity", "status", "embedding",
                "created_at", "updated_at",
            ],
            "json_fields": ["trigger_keywords"],
        },
        "sessions": {
            "filter_base": "",
            "fields": [
                "id", "external_id", "collection", "session_count",
                "current_task", "active_files", "pending_actions",
                "created_at", "updated_at",
            ],
            "json_fields": ["active_files", "pending_actions"],
        },
        "awakening_briefs": {
            "filter_base": "",
            "fields": [
                "id", "session_id", "collection", "brief_json",
                "priority_action", "created_at",
            ],
            "json_fields": ["brief_json"],
        },
        "fact_edges": {
            "filter_base": "",
            "fields": [
                "from_fact", "to_fact", "relation",
                "confidence", "source", "created_at",
            ],
            "json_fields": [],
        },
    }

    total_fields = 0
    fully_populated = 0
    dead_fields = 0

    for table_name, table_def in table_defs.items():
        where, params = _build_where(table_def["filter_base"], collection)

        try:
            total = conn.execute(
                f"SELECT COUNT(*) FROM {table_name} {where}", params
            ).fetchone()[0]
        except Exception:
            report["tables"][table_name] = {"total": 0, "error": "table_not_found"}
            continue

        fields_report: dict = {}

        for field in table_def["fields"]:
            total_fields += 1
            field_info = _analyze_field(conn, table_name, field, where, params, total, table_def)

            rate = field_info.get("rate", 0.0)
            if rate >= 1.0:
                fully_populated += 1
            elif rate == 0.0:
                dead_fields += 1

            fields_report[field] = field_info

        # 分类统计
        if table_name == "facts" and total > 0:
            _append_distributions(conn, where, params, fields_report)

        report["tables"][table_name] = {
            "total": total,
            "fields": fields_report,
        }

    report["summary"] = {
        "total_fields": total_fields,
        "fully_populated": fully_populated,
        "dead_fields": dead_fields,
        "partial_fields": total_fields - fully_populated - dead_fields,
    }

    return report


def _build_where(filter_base: str, collection: str | None) -> tuple[str, list]:
    """构建参数化 WHERE 子句，避免 SQL 注入"""
    parts: list[str] = []
    params: list = []
    if filter_base:
        parts.append(filter_base)
    if collection:
        parts.append("collection=?")
        params.append(collection)
    if parts:
        return "WHERE " + " AND ".join(parts), params
    return "", params


def _analyze_field(
    conn, table_name: str, field: str, where: str, params: list, total: int, table_def: dict,
) -> dict:
    """分析单个字段的填充率、JSON 有效性、采样值"""
    extra = " AND" if where else " WHERE"
    try:
        non_null = conn.execute(
            f"SELECT COUNT(*) FROM {table_name} {where}"
            + extra + f" {field} IS NOT NULL AND {field} != ''",
            params,
        ).fetchone()[0]
    except Exception:
        return {"non_null": 0, "rate": 0.0, "error": True}

    rate = non_null / total if total > 0 else 0.0
    field_info: dict = {"non_null": non_null, "rate": round(rate, 2)}

    if field in table_def["json_fields"] and total > 0:
        _check_json_meaningful(conn, table_name, field, where, params, total, field_info)

    if non_null > 0 and field not in ("id", "created_at", "updated_at"):
        _sample_values(conn, table_name, field, where, params, field_info)

    return field_info


def _check_json_meaningful(
    conn, table_name: str, field: str, where: str, params: list, total: int, field_info: dict,
) -> None:
    """JSON 字段深度检查：排除空 [] 和 {}"""
    extra = " AND" if where else " WHERE"
    try:
        meaningful = conn.execute(
            f"SELECT COUNT(*) FROM {table_name} {where}"
            + extra + f" {field} IS NOT NULL"
            + f" AND {field} != '[]'"
            + f" AND {field} != '{{}}'"
            + f" AND {field} != ''",
            params,
        ).fetchone()[0]
        field_info["meaningful"] = meaningful
        field_info["meaningful_rate"] = round(meaningful / total, 2)
    except Exception:
        pass


def _sample_values(
    conn, table_name: str, field: str, where: str, params: list, field_info: dict,
) -> None:
    """采样典型值（最多 3 个）"""
    extra = " AND" if where else " WHERE"
    try:
        samples = conn.execute(
            f"SELECT DISTINCT {field} FROM {table_name} {where}"
            + extra + f" {field} IS NOT NULL AND {field} != ''"
            + f" AND {field} != '[]' AND {field} != '{{}}'"
            + f" LIMIT 3",
            params,
        ).fetchall()
        if samples:
            field_info["samples"] = [str(s[0])[:80] for s in samples]
    except Exception:
        pass


def _append_distributions(conn, where: str, params: list, fields_report: dict) -> None:
    """为 facts 表添加 category 和 source 分布统计"""
    try:
        cats = conn.execute(
            f"SELECT category, COUNT(*) as cnt FROM facts {where}"
            " GROUP BY category ORDER BY cnt DESC",
            params,
        ).fetchall()
        fields_report["_category_distribution"] = {
            r[0] or "null": r[1] for r in cats
        }
    except Exception:
        pass

    try:
        sources = conn.execute(
            f"SELECT source, COUNT(*) as cnt FROM facts {where}"
            " GROUP BY source ORDER BY cnt DESC",
            params,
        ).fetchall()
        fields_report["_source_distribution"] = {
            r[0] or "null": r[1] for r in sources
        }
    except Exception:
        pass


def format_report(report: dict) -> str:
    """格式化诊断报告为可读文本"""
    lines: list[str] = []
    lines.append("=" * 60)
    lines.append("  index1 Cognition — Schema Population Report")
    lines.append("=" * 60)

    summary = report.get("summary", {})
    lines.append(
        f"\n  Total fields: {summary.get('total_fields', 0)} | "
        f"Full: {summary.get('fully_populated', 0)} | "
        f"Partial: {summary.get('partial_fields', 0)} | "
        f"Dead: {summary.get('dead_fields', 0)}"
    )

    for table_name, table_data in report.get("tables", {}).items():
        total = table_data.get("total", 0)
        lines.append(f"\n{'─' * 50}")
        lines.append(f"  {table_name}  ({total} rows)")
        lines.append(f"{'─' * 50}")

        if table_data.get("error"):
            lines.append(f"  ⚠ {table_data['error']}")
            continue

        if total == 0:
            lines.append("  (empty)")
            continue

        fields = table_data.get("fields", {})
        for field_name, field_data in fields.items():
            if field_name.startswith("_"):
                # 分布统计
                lines.append(f"\n  {field_name.lstrip('_')}:")
                for k, v in field_data.items():
                    lines.append(f"    {k}: {v}")
                continue

            rate = field_data.get("rate", 0.0)
            bar = _progress_bar(rate)
            meaningful = field_data.get("meaningful_rate")
            suffix = ""
            if meaningful is not None and meaningful != rate:
                suffix = f" (meaningful: {meaningful:.0%})"

            lines.append(f"  {field_name:<25} {bar} {rate:>5.0%}{suffix}")

    lines.append(f"\n{'=' * 60}")
    return "\n".join(lines)


def _progress_bar(rate: float, width: int = 20) -> str:
    """生成进度条"""
    filled = int(rate * width)
    return "█" * filled + "░" * (width - filled)
