{% extends "layout.html" %}

{% block title %}生物遗传图谱 - 家谱管理系统{% endblock %}

{% block extra_css %}
<style>
    #tree-container { 
        width: 100%; 
        height: 700px; 
        background: white; 
        border: 1px solid #e9ecef; 
        border-radius: 8px;
        margin-top: 10px;
        box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
        position: relative;
        overflow: auto;
    }
    .node rect, .node circle { 
        stroke-width: 2px; 
        filter: drop-shadow(0 2px 4px rgba(0,0,0,0.1));
    }
    .node text { font: 13px 'Microsoft YaHei', sans-serif; }
    .node .node-name { font-size: 13px; font-weight: 500; fill: #334155; }
    
    /* 样图一致：较粗的细实线、浅灰蓝色，显得专业 */
    .link { fill: none; stroke: #94A3B8; stroke-width: 2px; stroke-linejoin: round; }
    
    /* 关系标签文字，取消白色粗描边，因为已有胶囊形背景 */
    .link-label { font-size: 11px; fill: #64748B; font-weight: 500; }
    .link-label-sibling { fill: #64748B; }

    /* 男女形状与颜色区分：男性方形（蓝），女性圆形（粉红），添加轻微圆角与投影 */
    .node-male rect { stroke: #3B82F6; fill: #EFF6FF; rx: 8px; ry: 8px; }
    .node-female circle { stroke: #EC4899; fill: #FDF2F8; }
    
    /* 未知性别默认 */
    .node-leaf circle, .node-internal circle { stroke: #94A3B8; fill: #F8FAFC; }
    .node-male circle { stroke: none; fill: none; } /* 清除可能的干扰 */

    /* 样图一致：全部细实线 */
    .link-parent-child { stroke: #333; stroke-dasharray: none; }
    .link-spouse { stroke: #333; stroke-dasharray: none; stroke-width: 1.2px; }
    .link-sibling { stroke: #333; stroke-dasharray: none; stroke-width: 1.2px; }

    /* 右键菜单样式 */
    .context-menu {
        position: absolute;
        display: none;
        background: white;
        border: 1px solid #ccc;
        box-shadow: 2px 2px 10px rgba(0,0,0,0.2);
        z-index: 1000;
        border-radius: 4px;
        padding: 5px 0;
        min-width: 120px;
    }
    .context-menu-item {
        padding: 8px 15px;
        cursor: pointer;
        font-size: 14px;
        color: #333;
    }
    .context-menu-item:hover {
        background-color: #f8f9fa;
        color: #0d6efd;
    }
    .context-menu-item i {
        margin-right: 8px;
    }
</style>
{% endblock %}

{% block content %}
<div class="d-flex justify-content-between align-items-center mb-3">
    <h2><i class="bi bi-diagram-3"></i> 家谱关系树状图</h2>
    <!-- <p class="text-muted mb-0">基于父子/母子关系的生物遗传图谱</p> -->
</div>

    <div class="alert alert-light border small py-2">
        <i class="bi bi-info-circle me-1"></i> 提示：图中按生物遗传图谱格式展示。支持拖拽建立关系，右键点击成员可查看、编辑或新增。
    </div>

    <div id="tree-container">
        <!-- 右键菜单 -->
        <div id="contextMenu" class="context-menu">
            <div class="context-menu-item" onclick="menuAction('detail')"><i class="bi bi-eye"></i>查看成员</div>
            <div class="context-menu-item" onclick="menuAction('edit')"><i class="bi bi-pencil"></i>编辑成员</div>
            <div class="context-menu-item" onclick="menuAction('add')"><i class="bi bi-plus-lg"></i>新增成员</div>
        </div>
    </div>

    <!-- 关系选择弹窗 -->
    <div class="modal fade" id="relationModal" tabindex="-1">
        <div class="modal-dialog modal-sm">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title">建立关系</h5>
                    <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
                </div>
                <div class="modal-body">
                    <p id="relationInfo" class="small mb-3"></p>
                    <input type="hidden" id="sourceMid">
                    <input type="hidden" id="targetMid">
                    <div class="mb-3">
                        <label class="form-label small">关系类型</label>
                        <select id="relType" class="form-select form-select-sm">
                            <option value="1">是其 儿子/女儿</option>
                            <option value="10">是其 妻子/丈夫</option>
                            <option value="11">是其 兄弟</option>
                            <option value="12">是其 姐妹</option>
                        </select>
                    </div>
                    <div class="mb-3">
                        <label class="form-label small">子类型</label>
                        <select id="subRelType" class="form-select form-select-sm">
                            <option value="0">亲生/正妻</option>
                            <option value="1">养子/女</option>
                            <option value="2">过继</option>
                        </select>
                    </div>
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-sm btn-secondary" data-bs-dismiss="modal">取消</button>
                    <button type="button" class="btn btn-sm btn-primary" onclick="saveRelation()">保存关系</button>
                </div>
            </div>
        </div>
    </div>
{% endblock %}

{% block extra_js %}
<script src="{{ url_for('static', filename='js/d3.min.js') }}"></script>
<script>
    (function() {
        if (typeof d3 === 'undefined') {
            var container = document.getElementById('tree-container');
            if (container) container.innerHTML = '<div class="h-100 d-flex align-items-center justify-content-center text-danger small">D3.js 未加载，请检查网络或稍后重试。</div>';
        }
    })();
    let currentData = null;
    let dragSource = null;
    let dragTarget = null;
    let selectedMid = null; // 当前选中的成员 ID
    const relationModal = new bootstrap.Modal(document.getElementById('relationModal'));
    const contextMenu = document.getElementById('contextMenu');

    // 隐藏右键菜单
    window.addEventListener('click', () => {
        contextMenu.style.display = 'none';
    });

    // 处理菜单点击
    function menuAction(type) {
        if (!selectedMid && type !== 'add') return;
        
        switch(type) {
            case 'detail':
                window.location.href = `/manager/member_detail/${selectedMid}`;
                break;
            case 'edit':
                window.location.href = `/manager/edit_member/${selectedMid}`;
                break;
            case 'add':
                window.location.href = '/manager/add_member';
                break;
        }
    }

    // 获取数据并渲染
    function loadTree() {
        if (typeof d3 === 'undefined') return;
        fetch('/manager/api/tree_data')
            .then(response => response.json())
            .then(data => {
                currentData = data;
                renderTree(data);
            });
    }

    if (typeof d3 !== 'undefined') loadTree();

    function renderTree(data) {
        const container = document.getElementById('tree-container');
        container.innerHTML = '';
        container.appendChild(contextMenu);

        try {
            const { members, relations } = data;
            if (!members || members.length === 0) {
                container.innerHTML = '<div class="h-100 d-flex align-items-center justify-content-center text-muted">暂无成员数据，无法生成关系图。</div>';
                return;
            }

        const nodes = members.map(m => ({ id: m.id, name: m.name, simplified_name: m.simplified_name, sex: m.sex }));
        const hierarchicalLinks = relations.filter(r => r.relation_type === 1 || r.relation_type === 2)
                                          .map(r => ({ source: r.parent_mid, target: r.child_mid }));
        const spouseLinks = relations.filter(r => r.relation_type === 10);
        const otherLinks = relations.filter(r => r.relation_type >= 11);

        const childIds = new Set(hierarchicalLinks.map(l => l.target));
        const allSpouseIds = new Set(spouseLinks.map(l => l.child_mid));
        const roots = nodes.filter(n => !childIds.has(n.id) && !allSpouseIds.has(n.id));

        function buildHierarchy(nodeId, processedNodes = new Set()) {
            const node = nodes.find(n => n.id === nodeId);
            if (!node || processedNodes.has(nodeId)) return null;
            processedNodes.add(nodeId);

            const children = hierarchicalLinks.filter(l => l.source === nodeId)
                                .map(l => buildHierarchy(l.target, processedNodes))
                                .filter(c => c !== null);
            
            const spouses = spouseLinks.filter(l => l.parent_mid === nodeId)
                                .map(l => {
                                    const spouseId = l.child_mid;
                                    if (!childIds.has(spouseId)) {
                                        const sNode = nodes.find(n => n.id === spouseId);
                                        if (sNode && !processedNodes.has(spouseId)) {
                                            processedNodes.add(spouseId);
                                            return { id: sNode.id, name: sNode.name, simplified_name: sNode.simplified_name, sex: sNode.sex, isSpouseNode: true, children: [] };
                                        }
                                    }
                                    return null;
                                })
                                .filter(s => s !== null);

            return { id: node.id, name: node.name, simplified_name: node.simplified_name, sex: node.sex, children: spouses.concat(children) };
        }

        let treeData;
        if (roots.length > 1) {
            treeData = { name: "家谱根源", children: roots.map(root => buildHierarchy(root.id)).filter(r => r !== null) };
        } else if (roots.length === 1) {
            treeData = buildHierarchy(roots[0].id);
        } else {
            treeData = buildHierarchy(nodes[0].id);
        }

        const margin = {top: 80, right: 60, bottom: 80, left: 60};
        const containerWidth = document.getElementById('tree-container').offsetWidth;

        let rootNode = d3.hierarchy(treeData, d => (d && d.children) || []);
        
        // 动态调整间距，保证节点绝对不重叠，长辈/同辈/配偶使用固定基础间距
        const nodeWidth = 90; // 基础宽度
        const nodeHeight = 220; // 基础高度
        const treemap = d3.tree().nodeSize([nodeWidth, nodeHeight]).separation((a, b) => {
            const aSp = a.data && a.data.isSpouseNode;
            const bSp = b.data && b.data.isSpouseNode;
            if (aSp || bSp) return 1.8;
            return a.parent === b.parent ? 1.6 : 2.5;
        });
        
        let nodesHier = treemap(rootNode);

        // 样图一致：配偶与当事人同代、同一水平线并排，且水平至少间隔 spouseGap
        const spouseGap = 110;
        nodesHier.descendants().forEach(d => {
            if (d.data && d.data.isSpouseNode && d.parent) {
                d.y = d.parent.y;
                const dx = d.x - d.parent.x;
                if (Math.abs(dx) < spouseGap) d.x = d.parent.x + (dx >= 0 ? spouseGap : -spouseGap);
            }
        });

        // 计算边界以动态设置 SVG 宽高，实现自动滚动不挤压
        let x0 = Infinity;
        let x1 = -Infinity;
        let y1 = -Infinity;
        nodesHier.descendants().forEach(d => {
            if (d.x < x0) x0 = d.x;
            if (d.x > x1) x1 = d.x;
            if (d.y > y1) y1 = d.y;
        });

        const svgWidth = Math.max(containerWidth, x1 - x0 + margin.left + margin.right);
        const svgHeight = Math.max(600, y1 + margin.top + margin.bottom);
        
        // 偏移量使得最小的 x 在 margin.left 位置，且如果内容较少则居中
        const offsetX = Math.max(margin.left, (containerWidth - (x1 - x0)) / 2 - x0);

        const svg = d3.select("#tree-container").append("svg")
            .attr("width", svgWidth)
            .attr("height", svgHeight)
            .append("g")
            .attr("transform", `translate(${offsetX},${margin.top})`);

        // 节点圆圈半径（连线与节点共用），调大让图谱更清晰大气
        const circleR = 20;

        // 辅助函数：绘制精致的徽章式关系标签
        function addBadge(g, x, y, text) {
            const group = g.append("g").attr("transform", `translate(${x},${y})`);
            group.append("rect")
                .attr("x", -20).attr("y", -10)
                .attr("width", 40).attr("height", 20)
                .attr("rx", 10).attr("ry", 10) // 胶囊形状
                .attr("fill", "#fff")
                .attr("stroke", "#CBD5E1").attr("stroke-width", 1.2);
            group.append("text")
                .attr("class", "link-label")
                .attr("x", 0).attr("y", 0).attr("dy", "0.32em")
                .attr("text-anchor", "middle")
                .text(text);
        }

        // 连线：第二层连线设计（U型配偶线 + 亲子水平线）
        nodesHier.descendants().forEach(node => {
            if (!node.children || node.children.length === 0) return;
            const realChildren = (node.children || []).filter(c => c.data && !c.data.isSpouseNode);
            const spouses = (node.children || []).filter(c => c.data && c.data.isSpouseNode);

            const spouseY = node.y + 65; // 第一层：夫妻下方 U 型横线高度
            const num = (v) => (typeof v === 'number' && Number.isFinite(v) ? v : 0);

            // 夫妻关系：U型连线（增加第二层连线，主线在连出来）
            if (spouses.length > 0) {
                const x1 = Math.min(node.x, spouses[0].x), x2 = Math.max(node.x, spouses[0].x);
                const g = svg.append("g").attr("class", "link-group");
                const pathD = `M${num(node.x)},${num(node.y + circleR)} L${num(node.x)},${num(spouseY)} M${num(spouses[0].x)},${num(node.y + circleR)} L${num(spouses[0].x)},${num(spouseY)} M${num(x1)},${num(spouseY)} L${num(x2)},${num(spouseY)}`;
                g.append("path").attr("class", "link link-spouse").attr("d", pathD);
                
                addBadge(g, (x1 + x2) / 2, spouseY, "配偶");
            }

            if (realChildren.length === 0) return;
            
            const childrenY = realChildren[0].y;
            const minChildX = d3.min(realChildren, c => c.x);
            const maxChildX = d3.max(realChildren, c => c.x);
            
            const startX = spouses.length > 0 ? (node.x + spouses[0].x) / 2 : node.x;
            const startY = spouses.length > 0 ? spouseY : node.y + circleR;
            
            const sibsY = childrenY - 55; // 第二层：子女上方的水平分支线（拉高一点，给徽章留足空间）

            const g = svg.append("g").attr("class", "link-group");
            
            // 主线：从配偶U型线中点连到子女水平线
            let pathD = `M${num(startX)},${num(startY)} L${num(startX)},${num(sibsY)} L${num(minChildX)},${num(sibsY)} M${num(startX)},${num(sibsY)} L${num(maxChildX)},${num(sibsY)}`;
            
            // 短竖线：连到每个子女顶部
            realChildren.forEach(child => {
                pathD += ` M${num(child.x)},${num(sibsY)} L${num(child.x)},${num(child.y) - circleR}`;
            });
            g.append("path").attr("class", "link link-parent-child").attr("d", pathD);

            // 去除家谱根源到第一层的关系展示；下层亲子关系标记使用徽章式标签放在短竖线上，一目了然
            const isRootToFirst = !node.parent || !(node.data && node.data.id);
            if (!isRootToFirst && node.data) {
                realChildren.forEach(child => {
                    const pSex = node.data.sex;
                    const cSex = child.data && child.data.sex;
                    let label = "亲子";
                    if (pSex === 1) label = cSex === 1 ? "父子" : "父女";
                    else if (pSex === 2) label = cSex === 1 ? "母子" : "母女";
                    
                    const childLinkMidY = (sibsY + child.y - circleR) / 2;
                    addBadge(g, child.x, childLinkMidY, label);
                });
            }
        });

        // 兄弟/姐妹：上方 U 型连线避免穿透节点
        const idToPos = {};
        nodesHier.descendants().forEach(d => { if (d.data.id) idToPos[d.data.id] = { x: d.x, y: d.y }; });
        otherLinks.forEach(rel => {
            const s = idToPos[rel.parent_mid], t = idToPos[rel.child_mid];
            if (s && t) {
                const x1 = Math.min(s.x, t.x), x2 = Math.max(s.x, t.x);
                const y = s.y - circleR - 25; // 兄弟线在节点上方
                const g = svg.append("g");
                const pathD = `M${x1},${s.y - circleR} L${x1},${y} L${x2},${y} L${x2},${t.y - circleR}`;
                g.append("path").attr("class", "link link-sibling").attr("d", pathD);
                addBadge(g, (x1 + x2) / 2, y, rel.relation_type === 11 ? "兄弟" : "姐妹");
            }
        });

        const node = svg.selectAll(".node")
            .data(nodesHier.descendants())
            .enter().append("g")
            .attr("class", d => {
                let cls = "node" + (d.children ? " node--internal" : " node--leaf");
                if (d.data.sex === 1) cls += " node-male";
                else if (d.data.sex === 2) cls += " node-female";
                return cls;
            })
            .attr("transform", d => `translate(${d.x},${d.y})`)
            .on("contextmenu", function(event, d) {
                if (!d.data.id) return;
                event.preventDefault();
                selectedMid = d.data.id;
                const containerRect = document.getElementById('tree-container').getBoundingClientRect();
                contextMenu.style.display = 'block';
                contextMenu.style.left = (event.clientX - containerRect.left) + 'px';
                contextMenu.style.top = (event.clientY - containerRect.top) + 'px';
            })
            .call(d3.drag()
                .on("start", dragstarted)
                .on("drag", dragged)
                .on("end", dragended));

        // 图形：男性方形，女性圆形，更符合生物遗传图谱（不再需要性别符号）
        node.each(function(d) {
            const el = d3.select(this);
            if (d.data.sex === 1) { // 男性为方形
                el.append("rect")
                  .attr("x", -circleR).attr("y", -circleR)
                  .attr("width", circleR * 2).attr("height", circleR * 2)
                  .style("cursor", "grab");
            } else { // 女性为圆形（未知性别默认圆）
                el.append("circle")
                  .attr("r", circleR)
                  .style("cursor", "grab");
            }
        });
        // 人名：严格在图形下方，与图形底边留出间距，长名截断+悬停显示全名
        const nameOffsetY = circleR + 20;
        const maxNameLen = 8;
        function fullName(d) {
            if (!d.data) return '';
            return d.data.simplified_name ? `${d.data.name || ''} (${d.data.simplified_name})` : (d.data.name || '');
        }
        const nameGroup = node.append("g").attr("class", "node-name-wrap").attr("transform", "translate(0, " + nameOffsetY + ")");
        nameGroup.each(function(d) {
            const g = d3.select(this);
            const full = fullName(d);
            const disp = full.length <= maxNameLen ? full : full.slice(0, maxNameLen) + '…';
            
            // 允许指针事件以触发 tooltip (title)
            const textNode = g.append("text")
                .attr("class", "node-name")
                .attr("x", 0).attr("y", 0)
                .attr("text-anchor", "middle")
                .style("pointer-events", "all")
                .style("cursor", "default")
                .text(disp);
                
            if (full.length > maxNameLen) {
                textNode.append("title").text(full);
            }
        });

        function dragstarted(event, d) {
            if (!d.data.id) return;
            d3.select(this).raise().classed("active", true);
            d._currentX = d.x; d._currentY = d.y;
            dragSource = d.data;
        }

        function dragged(event, d) {
            d._currentX += event.dx; d._currentY += event.dy;
            d3.select(this).attr("transform", `translate(${d._currentX},${d._currentY})`);
        }

        function dragended(event, d) {
            d3.select(this).classed("active", false);
            const mouseX = event.sourceEvent.clientX, mouseY = event.sourceEvent.clientY;
            let foundNode = null;
            svg.selectAll(".node").each(function(nodeData) {
                if (!nodeData.data || nodeData.data.id === d.data.id || !nodeData.data.id) return;
                const rect = this.getBoundingClientRect();
                if (mouseX >= rect.left && mouseX <= rect.right && mouseY >= rect.top && mouseY <= rect.bottom) foundNode = nodeData.data;
            });
            if (foundNode && foundNode.id) {
                dragTarget = foundNode;
                document.getElementById('sourceMid').value = dragSource.id;
                document.getElementById('targetMid').value = dragTarget.id;
                document.getElementById('relationInfo').innerHTML = `确认将 <strong>${dragSource.name}</strong> 设定为 <strong>${dragTarget.name}</strong> 的关系人？`;
                relationModal.show();
            }
            setTimeout(() => { renderTree(currentData); }, 100);
        }
        } catch (err) {
            console.error('renderTree error:', err);
            container.innerHTML = '<div class="h-100 d-flex align-items-center justify-content-center text-danger small">关系图渲染出错，请刷新重试。<br>' + (err.message || '') + '</div>';
        }
    }

    function saveRelation() {
        const payload = {
            source_mid: document.getElementById('sourceMid').value,
            target_mid: document.getElementById('targetMid').value,
            relation_type: document.getElementById('relType').value,
            sub_relation_type: document.getElementById('subRelType').value
        };
        fetch('/manager/api/save_relation', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify(payload)
        }).then(res => res.json()).then(data => {
            if (data.success) { relationModal.hide(); loadTree(); }
            else { alert('保存失败: ' + data.message); }
        });
    }
</script>
{% endblock %}
