from __future__ import annotations

from typing import Any, Dict, List, Tuple


def empty_calculation_graph_option(title: str = "暂无图结构数据") -> Dict[str, Any]:
    return {
        "backgroundColor": "#f8fafc",
        "title": {"text": title, "left": "center", "top": 10, "textStyle": {"fontSize": 13}},
        "tooltip": {},
        "animationDuration": 300,
        "series": [
            {
                "type": "graph",
                "layout": "force",
                "roam": True,
                "label": {"show": True, "position": "right", "fontSize": 11},
                "data": [],
                "links": [],
                "categories": [],
                "force": {"repulsion": 240, "edgeLength": 110},
                "lineStyle": {"opacity": 0.7, "curveness": 0.12, "width": 1.0},
            }
        ],
    }


def _extract_graph_nodes_edges(payload: Any) -> Tuple[List[Dict[str, Any]], List[Dict[str, Any]]]:
    if not isinstance(payload, dict):
        return [], []
    nodes = payload.get("nodes", [])
    edges = payload.get("edges", [])
    if not isinstance(nodes, list):
        nodes = []
    if not isinstance(edges, list):
        edges = []
    return list(nodes), list(edges)


def _calculator_graph_label(node: Dict[str, Any]) -> str:
    kind = str(node.get("kind", "")).strip()
    if kind == "input_cell":
        neighbor_labels = node.get("neighbor_labels", {})
        if isinstance(neighbor_labels, dict):
            for direction in ("left", "up", "right", "down"):
                text = str(neighbor_labels.get(direction, "")).strip()
                if text:
                    return text
        names = [str(item).strip() for item in node.get("defined_names", []) if str(item).strip()]
        if names:
            return names[0]
    if kind == "unresolved_named_ref":
        return str(node.get("name", "")).strip() or str(node.get("id", "")).strip()
    sheet = str(node.get("sheet", "")).strip()
    cell = str(node.get("cell", "")).strip()
    if sheet and cell:
        return f"{sheet}:{cell}"
    return str(node.get("id", "")).strip()


def build_calculation_graph_view(
    payload: Any,
    *,
    max_nodes: int = 800,
    max_edges: int = 2200,
) -> Dict[str, Any]:
    nodes, edges = _extract_graph_nodes_edges(payload)
    if not nodes:
        return {
            "summary": "图结构：0 个节点，0 条连线",
            "option": empty_calculation_graph_option(),
            "nodes": [],
            "edges": [],
        }

    category_index = {"input_cell": 0, "formula_cell": 1, "referenced_cell": 2, "unresolved_named_ref": 3}
    categories = [
        {"name": "输入单元格"},
        {"name": "公式单元格"},
        {"name": "引用单元格"},
        {"name": "命名引用"},
    ]
    color_map = {
        "input_cell": "#2a9d8f",
        "formula_cell": "#e76f51",
        "referenced_cell": "#577590",
        "unresolved_named_ref": "#f4a261",
    }

    node_rows: List[Dict[str, Any]] = []
    node_ids: set[str] = set()
    for item in nodes[:max_nodes]:
        if not isinstance(item, dict):
            continue
        node_id = str(item.get("id", "")).strip()
        if not node_id:
            continue
        node_ids.add(node_id)
        kind = str(item.get("kind", "")).strip()
        node_rows.append(
            {
                "id": node_id,
                "name": _calculator_graph_label(item) or node_id,
                "category": category_index.get(kind, 2),
                "symbolSize": 20 if kind == "formula_cell" else 15,
                "itemStyle": {"color": color_map.get(kind, "#577590")},
            }
        )

    link_rows: List[Dict[str, Any]] = []
    for edge in edges[:max_edges]:
        if not isinstance(edge, dict):
            continue
        source = str(edge.get("from", "")).strip()
        target = str(edge.get("to", "")).strip()
        if not source or not target:
            continue
        if source not in node_ids or target not in node_ids:
            continue
        via = str(edge.get("via", "")).strip()
        link_rows.append(
            {
                "source": source,
                "target": target,
                "label": {"show": False},
                "lineStyle": {"width": 1.0, "opacity": 0.7},
                "value": via,
            }
        )

    option = {
        "backgroundColor": "#f8fafc",
        "tooltip": {"formatter": "{b}"},
        "legend": [{"data": [c["name"] for c in categories], "top": 4}],
        "animationDuration": 450,
        "series": [
            {
                "type": "graph",
                "layout": "force",
                "roam": True,
                "draggable": True,
                "label": {"show": True, "position": "right", "fontSize": 11},
                "data": node_rows,
                "links": link_rows,
                "categories": categories,
                "force": {"repulsion": 260, "edgeLength": [70, 150]},
                "lineStyle": {"opacity": 0.75, "curveness": 0.12, "width": 1.0},
            }
        ],
    }
    return {
        "summary": f"图结构：{len(node_rows)} 个节点，{len(link_rows)} 条连线",
        "option": option,
        "nodes": nodes,
        "edges": edges,
    }
