import json
import sys
from pathlib import Path

def generate_html_visualization(result_data: dict, cases_data: dict) -> str:
    merged_demands = result_data.get("merged_demands", [])
    mount_decisions = result_data.get("mount_decisions", [])

    # 构建 decision_map：demand_name → mounted_nodes
    decision_map = {}
    for d in mount_decisions:
        dec = d.get("decision", {})
        if isinstance(dec, dict):
            decision_map[d["demand_name"]] = dec.get("mounted_nodes", [])
        else:
            decision_map[d["demand_name"]] = []

    # 优先从 result_data 读取 case_info，如果没有则从 cases_data 构建
    if "case_info" in result_data:
        case_map = result_data["case_info"]
    else:
        case_map = {}
        for c in cases_data.get("cases", []):
            case_map[c["case_id"]] = {
                "title": c.get("title") or c.get("video_title") or c.get("post_title", ""),
                "images": c.get("images") or c.get("effect_images", []),
                "link": c.get("source_link") or c.get("video_url") or c.get("post_url", "")
            }

    nodes_js = []
    edges_js = []
    node_id = 0

    COLOR_CASE_BG = "#e3f2fd"
    COLOR_CASE_BORDER = "#2196f3"
    COLOR_DEMAND_BG = "#fff3e0"
    COLOR_DEMAND_BORDER = "#ff9800"

    for md in merged_demands:
        demand_id = node_id
        node_id += 1

        dn = md["demand_name"]
        
        # 从挂载决策中获取最终选择的节点
        mounted = decision_map.get(dn, [])
        node_tags = []
        for n in mounted:
            node_tags.append(f"{n['name']}")

        tags_str = " | ".join(node_tags) if node_tags else "无挂载节点"

        demand_label = f"<b>{dn}</b>\n\n[{tags_str}]"
        
        demand_title_html = f"""
            <div class='tooltip-title' style='background:{COLOR_DEMAND_BG}; border-color:{COLOR_DEMAND_BORDER}'>需求详情</div>
            <div class='tooltip-content'>
                <p><b>名称:</b> {dn}</p>
                <p><b>描述:</b> {md["description"]}</p>
                <p><b>挂载节点:</b> {tags_str}</p>
                {"".join(f"<p>· {n['name']}({n.get('source_type','')}) — {n.get('reason','')}</p>" for n in mounted)}
            </div>
        """

        nodes_js.append({
            "id": demand_id,
            "label": demand_label,
            "title": demand_title_html,
            "group": "demand",
            "level": 0  # 核心改动1：Demand 改为 Level 0 (根节点)
        })

        for cid in md.get("source_case_ids", []):
            case_id = node_id
            node_id += 1

            # 类型转换：case_info 的 key 可能是字符串
            cid_str = str(cid)
            case_info = case_map.get(cid_str) or case_map.get(cid, {"title": f"Case {cid}", "images": [], "link": ""})
            title_short = case_info['title'][:20] + "..." if len(case_info['title']) > 20 else case_info['title']
            case_label = f"<b>Case {cid}</b>\n{title_short}"

            img_html = ""
            if case_info['images']:
                img_url = case_info['images'][0]
                img_html = f'<img src="{img_url}" class="tooltip-img"/>'

            case_title_html = f"""
                <div class='tooltip-title' style='background:{COLOR_CASE_BG}; border-color:{COLOR_CASE_BORDER}'>帖子详情 (点击跳转)</div>
                <div class='tooltip-content'>
                    <p><b>ID:</b> {cid}</p>
                    <p><b>标题:</b> {case_info["title"]}</p>
                    {img_html}
                </div>
            """

            nodes_js.append({
                "id": case_id,
                "label": case_label,
                "title": case_title_html,
                "url": case_info['link'], 
                "group": "case",
                "level": 1  # 核心改动2：Case 改为 Level 1 (叶子节点)
            })

            # 核心改动3：在数据上把连线方向反转为 Demand -> Case
            edges_js.append({"from": demand_id, "to": case_id})

    html = f"""<!DOCTYPE html>
<html><head>
<meta charset="utf-8">
<meta name="referrer" content="no-referrer">
<title>Case → Demand 语义映射图</title>
<script src="https://unpkg.com/vis-network/standalone/umd/vis-network.min.js"></script>
<style>
  body {{ 
    margin: 0; 
    font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; 
    background-color: #f4f7f6; 
    overflow: hidden; 
  }}
  #graph {{ width: 100vw; height: 100vh; background-color: white; }}
  #header {{ 
    position: absolute; top: 10px; left: 20px; padding: 10px 20px; 
    display: flex; gap: 30px; align-items: center; 
    background: rgba(255, 255, 255, 0.9); box-shadow: 0 4px 10px rgba(0,0,0,0.1);
    border-radius: 8px; z-index: 10;
  }}
  .brand {{ font-size: 16px; font-weight: bold; color: #333; }}
  #legend {{ display: flex; gap: 15px; align-items: center; font-size: 13px; }}
  .legend-item {{ display: flex; align-items: center; gap: 6px; }}
  .dot {{ width: 14px; height: 14px; border-radius: 3px; border: 1px solid; }}
  div.vis-network div.vis-tooltip {{
    padding: 0; border: none; border-radius: 8px; background-color: white;
    box-shadow: 0 4px 15px rgba(0,0,0,0.25); font-size: 14px; max-width: 400px; overflow: hidden;
  }}
  .tooltip-title {{ padding: 10px 15px; font-weight: bold; border-bottom: 1px solid; color: #333; }}
  .tooltip-content {{ padding: 15px; color: #555; }}
  .tooltip-content p {{ margin: 0 0 10px 0; line-height: 1.5; }}
  .tooltip-img {{ max-width: 100%; max-height: 250px; display: block; margin-top: 10px; border-radius: 4px; border: 1px solid #eee; }}
</style>
</head><body>

<div id="header">
  <div class="brand">语义映射网络 (鼠标拖拽平移，滚轮缩放)</div>
  <div id="legend">
    <span class="legend-item"><span class="dot" style="background:{COLOR_CASE_BG}; border-color:{COLOR_CASE_BORDER}"></span> 帖子 (Case)</span>
    <span class="legend-item"><span class="dot" style="background:{COLOR_DEMAND_BG}; border-color:{COLOR_DEMAND_BORDER}"></span> 需求 (Demand)</span>
  </div>
</div>
<div id="graph"></div>

<script>
var nodesRaw = {json.dumps(nodes_js, ensure_ascii=False)};
var edgesRaw = {json.dumps(edges_js, ensure_ascii=False)};

nodesRaw.forEach(function(node) {{
    if (node.title && typeof node.title === 'string') {{
        var container = document.createElement('div');
        container.innerHTML = node.title;
        node.title = container;
    }}
}});

var nodes = new vis.DataSet(nodesRaw);
var edges = new vis.DataSet(edgesRaw);
var container = document.getElementById("graph");

var options = {{
  layout: {{
    hierarchical: {{
      direction: "DU",      /* 核心改动4：改为从下往上 (Down-Up) 生长。Level 0(Demand)在底，Level 1(Case)在顶 */
      sortMethod: "directed", 
      levelSeparation: 300,
      nodeSpacing: 180,
      treeSpacing: 350,
      parentCentralization: true /* 由于 Demand 在逻辑上成了父节点，这个属性会完美将它居中 */
    }}
  }},
  groups: {{
    useDefaultGroups: false,
    case: {{
      shape: "box",
      color: {{ background: "{COLOR_CASE_BG}", border: "{COLOR_CASE_BORDER}" }},
      font: {{ size: 14, multi: 'html', color: "#0d47a1" }},
      widthConstraint: {{ minimum: 150, maximum: 220 }},
      shapeProperties: {{ borderDashes: false, borderRadius: 6 }},
      margin: 12
    }},
    demand: {{
      shape: "box",
      color: {{ background: "{COLOR_DEMAND_BG}", border: "{COLOR_DEMAND_BORDER}" }},
      font: {{ size: 15, multi: 'html', color: "#e65100" }},
      widthConstraint: {{ minimum: 200, maximum: 300 }},
      shapeProperties: {{ borderDashes: false, borderRadius: 6 }},
      margin: 15
    }}
  }},
  edges: {{ 
    arrows: "from",   /* 核心改动5：虽然连线是 Demand->Case，但把箭头强制画在 Demand 一侧，看起来就是 Case->Demand */
    color: {{ color: "#b0bec5", highlight: "#78909c" }},
    smooth: {{ type: "cubicBezier", forceDirection: "vertical", roundness: 0.5 }},
    width: 1.5
  }},
  physics: {{ enabled: false }}, 
  interaction: {{ 
    hover: true, tooltipDelay: 100, dragView: true, zoomView: true 
  }}
}};

var network = new vis.Network(container, {{ nodes: nodes, edges: edges }}, options);

network.once("afterDrawing", function() {{
    if (nodesRaw.length > 0) {{
        network.focus(nodesRaw[0].id, {{
            scale: 1.0, 
            animation: false,
            offset: {{x: 0, y: -100}} 
        }});
    }}
}});

network.on("click", function(params) {{
    if (params.nodes.length > 0) {{
        var nodeData = nodes.get(params.nodes[0]);
        if (nodeData.url && nodeData.url.startsWith('http')) window.open(nodeData.url, '_blank');
    }}
}});

network.on("hoverNode", function(params) {{
    if (nodes.get(params.node).url) network.canvas.body.container.style.cursor = 'pointer';
}});
network.on("blurNode", function() {{
    network.canvas.body.container.style.cursor = 'default';
}});
</script>
</body></html>"""
    return html

def main():
    if len(sys.argv) < 2:
        print("用法: python visualize_results.py <match_nodes_result.json路径>")
        sys.exit(1)

    result_path = Path(sys.argv[1])
    if not result_path.exists():
        print(f"错误: 文件不存在: {result_path}")
        sys.exit(1)

    with open(result_path, "r", encoding="utf-8") as f:
        result_data = json.load(f)

    cases_path = result_path.parent / "02_cases.json"
    if not cases_path.exists():
        cases_data = {"cases": []}
    else:
        with open(cases_path, "r", encoding="utf-8") as f:
            cases_data = json.load(f)

    html = generate_html_visualization(result_data, cases_data)

    output_path = result_path.parent / "match_nodes_graph.html"
    with open(output_path, "w", encoding="utf-8") as f:
        f.write(html)

    print(f"[OK] Visualization generated: {output_path}")

if __name__ == "__main__":
    main()