"""
Architecture Visualization Layer — Phase 7 of Kodara pipeline.

Exports the dependency graph in multiple formats:
  - JSON graph (for programmatic use / frontend)
  - Graphviz DOT (for rendering with dot/graphviz tools)

Future: D3.js interactive export, Mermaid diagram format.
"""

from __future__ import annotations

import json
from pathlib import Path
from typing import Optional

from ..memory.store import KodaraIndex


# Language → node fill color (Graphviz color names)
LANG_COLORS = {
    "python": "lightyellow",
    "javascript": "lightgreen",
    "typescript": "lightskyblue",
    "go": "lightcyan",
    "rust": "lightsalmon",
    "java": "lavender",
    "csharp": "mistyrose",
    "php": "thistle",
}


class ArchitectureVisualizer:
    """Exports a KodaraIndex as a visual architecture representation."""

    # ── JSON ────────────────────────────────────────────────────────────────

    def to_json(self, index: KodaraIndex) -> dict:
        """
        Export as a JSON graph suitable for D3.js, Cytoscape, or any
        graph visualization library.
        """
        nodes = []
        for path, mod in index.modules.items():
            nodes.append({
                "id": path,
                "label": mod.get("module_name", path),
                "language": mod.get("language", ""),
                "classes": mod.get("classes", []),
                "function_count": len(mod.get("functions", [])),
                "summary": mod.get("summary", ""),
                "in_degree": sum(
                    1 for e in index.graph_edges if e.get("to") == path
                ),
                "out_degree": sum(
                    1 for e in index.graph_edges if e.get("from") == path
                ),
            })

        # Sort nodes: most-imported first (architectural hubs)
        nodes.sort(key=lambda n: -n["in_degree"])

        return {
            "repo": index.repo_id,
            "display_name": index.display_name,
            "source_root": index.source_root,
            "indexed_at": index.indexed_at,
            "stats": {
                "total_files": index.file_count,
                "total_dependencies": len(index.graph_edges),
                "languages": index.language_counts,
            },
            "nodes": nodes,
            "edges": index.graph_edges,
        }

    # ── Graphviz DOT ────────────────────────────────────────────────────────

    def to_graphviz(self, index: KodaraIndex, show_classes: bool = True) -> str:
        """
        Export as Graphviz DOT format.

        Render with:
          dot -Tpng graph.dot -o architecture.png
          dot -Tsvg graph.dot -o architecture.svg
        """
        lines = [
            f'digraph "{index.display_name}" {{',
            "    rankdir=LR;",
            "    graph [fontname=Helvetica, fontsize=12];",
            "    node [shape=box, style=filled, fontname=Helvetica, fontsize=10];",
            "    edge [fontname=Helvetica, fontsize=8, color=gray50];",
            "",
        ]

        # Group nodes by language using subgraphs
        by_lang: dict[str, list[tuple[str, dict]]] = {}
        for path, mod in index.modules.items():
            lang = mod.get("language", "other")
            by_lang.setdefault(lang, []).append((path, mod))

        for lang, items in sorted(by_lang.items()):
            color = LANG_COLORS.get(lang, "lightgray")
            lines.append(f"    subgraph cluster_{lang} {{")
            lines.append(f'        label="{lang}";')
            lines.append(f"        style=dashed;")

            for path, mod in items:
                node_id = self._node_id(path)
                label = mod.get("module_name", path)
                if show_classes and mod.get("classes"):
                    cls_str = "\\n".join(mod["classes"][:3])
                    label = f"{label}\\n[{cls_str}]"
                lines.append(
                    f'        {node_id} [label="{label}", fillcolor={color}];'
                )
            lines.append("    }")
            lines.append("")

        # Edges
        for edge in index.graph_edges:
            src = self._node_id(edge["from"])
            dst = self._node_id(edge["to"])
            lines.append(f"    {src} -> {dst};")

        lines.append("}")
        return "\n".join(lines)

    # ── Mermaid ──────────────────────────────────────────────────────────────

    def to_mermaid(self, index: KodaraIndex, max_nodes: int = 30) -> str:
        """
        Export as Mermaid flowchart (paste into any Mermaid renderer).
        Limits to max_nodes most-connected nodes to keep diagrams readable.
        """
        # Rank by total degree
        degree: dict[str, int] = {}
        for edge in index.graph_edges:
            degree[edge["from"]] = degree.get(edge["from"], 0) + 1
            degree[edge["to"]] = degree.get(edge["to"], 0) + 1

        top_nodes = set(
            sorted(degree, key=lambda x: -degree[x])[:max_nodes]
        )

        lines = ["graph LR"]
        for path in top_nodes:
            mod = index.modules.get(path, {})
            label = mod.get("module_name", path).replace('"', "'")
            node_id = self._mermaid_id(path)
            lines.append(f'    {node_id}["{label}"]')

        for edge in index.graph_edges:
            if edge["from"] in top_nodes and edge["to"] in top_nodes:
                src = self._mermaid_id(edge["from"])
                dst = self._mermaid_id(edge["to"])
                lines.append(f"    {src} --> {dst}")

        return "\n".join(lines)

    # ── Save helpers ─────────────────────────────────────────────────────────

    def save_json(self, index: KodaraIndex, output_path: str | Path) -> None:
        data = self.to_json(index)
        Path(output_path).write_text(
            json.dumps(data, indent=2, ensure_ascii=False), encoding="utf-8"
        )

    def save_graphviz(self, index: KodaraIndex, output_path: str | Path) -> None:
        Path(output_path).write_text(self.to_graphviz(index), encoding="utf-8")

    def save_mermaid(self, index: KodaraIndex, output_path: str | Path) -> None:
        Path(output_path).write_text(self.to_mermaid(index), encoding="utf-8")

    # ── Utilities ────────────────────────────────────────────────────────────

    @staticmethod
    def _node_id(path: str) -> str:
        """Convert a file path to a valid Graphviz node identifier."""
        return (
            path.replace("/", "_")
            .replace("\\", "_")
            .replace(".", "_")
            .replace("-", "_")
        )

    @staticmethod
    def _mermaid_id(path: str) -> str:
        """Convert a file path to a valid Mermaid node identifier."""
        return (
            path.replace("/", "_")
            .replace("\\", "_")
            .replace(".", "_")
            .replace("-", "_")
        )
