"""Enhanced MCP summary for v2.0 - uses all 3 graphs."""

from pathlib import Path
from collections import Counter

from mesh.analysis.builder import (
    detect_duplicates,
    detect_circular_calls,
    detect_naming_violations,
)


def approx_tokens(text: str) -> int:
    """Approximate token count."""
    return max(1, len(text) // 4)


def _get_patterns(call_graph, codebase_root: Path) -> str:
    """Detect architectural pattern from directory structure."""
    try:
        dirs = {p.name.lower() for p in codebase_root.iterdir() if p.is_dir()}
        if (
            {"service", "repo", "dto"} & dirs
            or {"services", "repos", "dtos"} & dirs
            or {"service", "repository"} & dirs
        ):
            return "service-repo-dto"
        if {"controller", "model", "view"} & dirs or {
            "controllers",
            "models",
            "views",
        } & dirs:
            return "MVC"
        if {"route", "handler"} & dirs or {"routes", "handlers"} & dirs:
            return "route-handler"
        if {"core", "api", "domain"} & dirs:
            return "layered"
        return "unknown"
    except Exception:
        return "unknown"


def _get_top_violations(call_graph) -> list[str]:
    """Return top violations as short strings."""
    lines = []
    try:
        dups = detect_duplicates(call_graph)
        for v in dups[:2]:
            name = v.get("message", "").split("(")[0]
            files = len(v.get("related_files", [])) + 1
            lines.append(f"  duplicate: {name}() in {files} files")
    except Exception:
        pass
    try:
        names = detect_naming_violations(call_graph)
        for v in names[:1]:
            msg = v.get("message", "")
            parts = msg.split()
            if parts:
                lines.append(f"  naming: {parts[0]}")
    except Exception:
        pass
    try:
        circs = detect_circular_calls(call_graph)
        for v in circs[:1]:
            msg = v.get("message", "")[:60]
            lines.append(f"  circular: {msg}")
    except Exception:
        pass
    return lines


def _get_reuse_hints(call_graph) -> list[str]:
    """Return most-called functions as reuse hints."""
    try:
        nodes = {n.get("id"): n for n in call_graph.nodes() if n.get("id")}
        in_degrees = {}
        for node_data in call_graph.nodes():
            node_id = node_data.get("id", "")
            if node_id:
                in_degrees[node_id] = call_graph.in_degree(node_id)
        top = sorted(in_degrees.items(), key=lambda x: x[1], reverse=True)[:5]
        hints = []
        for node_id, degree in top:
            if degree < 3:
                break
            node = nodes.get(node_id, {})
            name = node.get("name", node_id)
            hints.append(f"  {name} (called {degree}x)")
        return hints
    except Exception:
        return []


def generate_summary(call_graph, type_deps, codebase_root, max_tokens=210):
    """Generate full architectural summary using all 3 graphs."""
    lines = []

    # Header
    total_funcs = call_graph.node_count if call_graph else 0
    total_types = type_deps.node_count if type_deps else 0

    files_dict = {}
    if call_graph:
        for node_data in call_graph.nodes():
            fp = node_data.get("file_path", "unknown")
            try:
                rel = Path(fp).relative_to(codebase_root)
            except Exception:
                rel = Path(fp)
            files_dict[str(rel)] = files_dict.get(str(rel), 0) + 1

    total_files = len(files_dict)

    lines.append(
        f"[MESH v2 | {codebase_root.name} | {total_files} files | {total_funcs} funcs | {total_types} types]"
    )

    # Naming
    if call_graph:
        snake = camel = pascal = 0
        for node_data in call_graph.nodes():
            name = node_data.get("name", "")
            if "_" in name and name == name.lower():
                snake += 1
            elif name and name[0].islower():
                camel += 1
            elif name and name[0].isupper():
                pascal += 1

        total = snake + camel + pascal
        if total > 0:
            pct = (snake * 100) // total
            lines.append(f"NAMING: snake_case ({pct}%)")

    # Violations
    if call_graph:
        dups = detect_duplicates(call_graph)
        circs = detect_circular_calls(call_graph)
        naming = detect_naming_violations(call_graph)
        lines.append(f"VIOLATIONS: {len(dups) + len(circs) + len(naming)}")

    # Top files
    if files_dict:
        lines.append("")
        lines.append("TOP FILES (by functions):")
        for fp, count in sorted(files_dict.items(), key=lambda x: -x[1])[:4]:
            lines.append(f"  {fp}: {count}")

    # Top classes
    classes_dict = {}
    if type_deps:
        for node in type_deps.nodes():
            fp = node.get("file_path", "")
            try:
                rel = Path(fp).relative_to(codebase_root)
            except Exception:
                rel = Path(fp)
            key = str(rel)
            classes_dict[key] = classes_dict.get(key, 0) + 1

    if classes_dict:
        lines.append("")
        lines.append("TOP CLASSES (by count):")
        for fp, count in sorted(classes_dict.items(), key=lambda kv: -kv[1])[:3]:
            lines.append(f"  {fp}: {count}")

    # Inheritance
    if type_deps:
        lines.append("")
        lines.append("SAMPLE INHERITANCE:")
        inh_count = 0
        for node in type_deps.nodes():
            bases = node.get("bases", [])
            if bases and inh_count < 2:
                name = node.get("name", "?")
                lines.append(f"  {name} -> {', '.join(bases)}")
                inh_count += 1

    # Top called functions
    if call_graph and call_graph.edge_count > 0:
        called_counter = Counter()
        for edge in call_graph.get_all_edges():
            called_counter[edge.get("to_id", "")] += 1

        func_names = {}
        for node in call_graph.nodes():
            nid = node.get("id", "")
            func_names[nid] = node.get("name", nid[:8])

        if called_counter:
            lines.append("")
            lines.append("TOP CALLED FUNCTIONS:")
            for called_id, count in called_counter.most_common(2):
                name = func_names.get(called_id, called_id[:8])
                lines.append(f"  {name}: called {count}x")

    # PATTERNS section
    if call_graph and codebase_root:
        pattern = _get_patterns(call_graph, codebase_root)
        if pattern != "unknown":
            lines.append(f"PATTERNS: {pattern}")

    # TOP VIOLATIONS section
    if call_graph:
        violation_lines = _get_top_violations(call_graph)
        if violation_lines:
            lines.append("TOP VIOLATIONS:")
            lines.extend(violation_lines[:2])

    # REUSE section
    if call_graph:
        reuse_hints = _get_reuse_hints(call_graph)
        if reuse_hints:
            lines.append("REUSE:")
            lines.extend(reuse_hints[:3])

    summary = "\n".join(lines)

    return summary


def get_architectural_context(call_graph, data_flow, type_deps, codebase_root):
    """Get architectural context for AI session injection."""
    return generate_summary(call_graph, type_deps, codebase_root)
