{% extends "layout.html" %}

{% block title %}{{ '编辑' if member else '录入' }}成员 - 家谱管理系统{% endblock %}

{% block extra_css %}
<style>
    .split-container { display: flex; height: calc(100vh - 100px); overflow: hidden; }
    .form-panel { flex: 1.2; padding: 20px; overflow-y: auto; border-right: 1px solid #dee2e6; }
    .image-panel { flex: 0.8; padding: 20px; background: #f8f9fa; display: flex; flex-direction: column; }
    .image-viewer { flex: 1; border: 1px solid #ccc; background: white; overflow: hidden; text-align: center; position: relative; }
    .image-viewer img { max-width: 100%; height: auto; transition: transform 0.2s, filter 0.2s; transform-origin: top left; cursor: grab; }
    .image-viewer img.dragging { cursor: grabbing; }
    
    /* 放大镜样式 */
    .magnifier-glass {
        position: absolute;
        border: 3px solid #000;
        border-radius: 50%;
        cursor: none;
        width: 150px;
        height: 150px;
        box-shadow: 0 0 10px rgba(0,0,0,0.5);
        display: none;
        z-index: 1000;
        background-repeat: no-repeat;
        background-color: white;
        pointer-events: none;
    }

    /* Image Viewer & Dragging */
    .image-viewer { 
        flex: 1; 
        border: 1px solid #ccc; 
        background: #f0f0f0; 
        overflow: hidden; 
        text-align: center; 
        position: relative; 
        cursor: grab;
        user-select: none;
    }
    .image-viewer:active {
        cursor: grabbing;
    }
    
    .image-wrapper {
        display: inline-block;
        transition: transform 0.2s ease-out;
        transform-origin: center center;
        position: absolute;
        /* Initial centering will be handled by JS or CSS translate */
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
    }

    .image-wrapper img {
        max-width: 100%;
        max-height: 100vh;
        display: block;
        pointer-events: none;
        user-select: none;
        transition: filter 0.2s;
    }

    .image-toolbar {
        background: #e9ecef;
        padding: 5px 10px;
        border-bottom: 1px solid #dee2e6;
        display: flex;
        gap: 10px;
        align-items: center;
        flex-wrap: wrap;
    }
    .image-toolbar .btn-group-xs > .btn, .image-toolbar .btn-sm {
        padding: 0.25rem 0.5rem;
        font-size: 0.875rem;
    }
    .filter-controls { display: flex; align-items: center; gap: 5px; font-size: 0.8rem; }
    .filter-controls input[type=range] { width: 80px; }
    .page-nav { margin-bottom: 10px; display: flex; gap: 10px; align-items: center; }
    .section-title { border-left: 4px solid #0d6efd; padding-left: 10px; margin: 25px 0 15px; font-weight: bold; color: #333; }
</style>
{% endblock %}

{% block content %}
<div class="split-container">
    <!-- 左侧：录入/编辑表单 -->
    <div class="form-panel">
        <div class="card shadow-sm mb-4">
            <div class="card-header bg-primary text-white d-flex justify-content-between align-items-center">
                <h5 class="mb-0">{{ '编辑成员信息' if member else '录入新成员' }}</h5>
                <a href="{{ url_for('members') }}" class="btn btn-sm btn-light">返回列表</a>
            </div>
            <div class="card-body">
                <form method="POST">
                    <input type="hidden" name="source_record_id" value="{{ source_record_id if source_record_id else (member.source_record_id if member and member.source_record_id else '') }}">
                    <input type="hidden" name="source_index" value="">
                    <div class="section-title">核心信息 (必填)</div>
                    <div class="row g-3">
                        <div class="col-md-6">
                            <label class="form-label">姓名（繁体） <span class="text-danger">*</span></label>
                            <input type="text" name="name" class="form-control" required value="{{ member.name if member else '' }}">
                        </div>
                        <div class="col-md-6">
                            <label class="form-label">姓名（简体）</label>
                            <input type="text" name="simplified_name" class="form-control" value="{{ member.simplified_name if member else '' }}">
                        </div>
                        <div class="col-md-6">
                            <label class="form-label">性别 <span class="text-danger">*</span></label>
                            <select name="sex" class="form-select" required>
                                <option value="1" {{ 'selected' if member and member.sex == 1 else '' }}>男</option>
                                <option value="2" {{ 'selected' if member and member.sex == 2 else '' }}>女</option>
                            </select>
                        </div>
                        <div class="col-md-6">
                            <label class="form-label">出生日期 <span class="text-danger">*</span></label>
                            <div class="input-group has-validation">
                                {% set birthday_val = member.birthday_date if member and member.birthday_date != '未知' else '' %}
                                <input type="date" name="birthday" class="form-control" required value="{{ birthday_val }}" onchange="validateAge()">
                                <div class="input-group-text bg-white">
                                    <input class="form-check-input mt-0" type="checkbox" id="birthdayUnknown" onchange="toggleBirthdayUnknown()" {{ 'checked' if member and member.birthday_date == '未知' else '' }}>
                                    <label class="form-check-label ms-1 small user-select-none" for="birthdayUnknown">不详</label>
                                </div>
                                <div class="invalid-feedback" id="ageFeedback"></div>
                            </div>
                        </div>
                    </div>

                    <div class="section-title">关系录入 (选择关联成员及关系)</div>
                    <div class="row g-3">
                        <div class="col-md-5">
                            <label class="form-label">关联成员</label>
                            <select name="related_mid" class="form-select">
                                <option value="">-- 请选择 --</option>
                                {% for m in all_members %}
                                <option value="{{ m.id }}" data-birthday="{{ m.birthday }}" {{ 'selected' if current_relation and current_relation.parent_mid == m.id else '' }}>
                                    {{ m.name }} (ID: {{ m.id }})
                                </option>
                                {% endfor %}
                            </select>
                        </div>
                        <div class="col-md-4">
                            <label class="form-label">关系类型</label>
                            <select name="relation_type" class="form-select">
                                <option value="">-- 请选择 --</option>
                                <option value="1" {{ 'selected' if current_relation and current_relation.relation_type == 1 else '' }}>父子 (关联人为父)</option>
                                <option value="2" {{ 'selected' if current_relation and current_relation.relation_type == 2 else '' }}>母子 (关联人为母)</option>
                                <option value="10" {{ 'selected' if current_relation and current_relation.relation_type == 10 else '' }}>夫妻</option>
                                <option value="11" {{ 'selected' if current_relation and current_relation.relation_type == 11 else '' }}>兄弟</option>
                                <option value="12" {{ 'selected' if current_relation and current_relation.relation_type == 12 else '' }}>姐妹</option>
                            </select>
                        </div>
                        <div class="col-md-3">
                            <label class="form-label">子类型</label>
                            <select name="sub_relation_type" class="form-select">
                                <option value="0" {{ 'selected' if current_relation and current_relation.sub_relation_type == 0 else '' }}>亲生/正妻</option>
                                <option value="1" {{ 'selected' if current_relation and current_relation.sub_relation_type == 1 else '' }}>养父</option>
                                <option value="2" {{ 'selected' if current_relation and current_relation.sub_relation_type == 2 else '' }}>过继</option>
                                <option value="10" {{ 'selected' if current_relation and current_relation.sub_relation_type == 10 else '' }}>妾</option>
                                <option value="11" {{ 'selected' if current_relation and current_relation.sub_relation_type == 11 else '' }}>外室</option>
                            </select>
                        </div>
                    </div>

                    <div class="section-title">谱系详情</div>
                    <div class="row g-3">
                        <div class="col-md-4">
                            <label class="form-label">曾用名</label>
                            <input type="text" name="former_name" class="form-control" value="{{ member.former_name if member else '' }}">
                        </div>
                        <div class="col-md-4">
                            <label class="form-label">幼名/乳名</label>
                            <input type="text" name="childhood_name" class="form-control" value="{{ member.childhood_name if member else '' }}">
                        </div>
                        <div class="col-md-4">
                            <label class="form-label">字辈</label>
                            <input type="text" name="name_word" class="form-control" value="{{ member.name_word if member else '' }}">
                        </div>
                        <div class="col-md-4">
                            <label class="form-label">堂内排行</label>
                            <input type="text" name="family_rank" class="form-control" value="{{ member.family_rank if member else '' }}">
                        </div>
                        <div class="col-md-4">
                            <label class="form-label">世系世代</label>
                            <input type="text" name="name_word_generation" class="form-control" value="{{ member.name_word_generation if member else '' }}">
                        </div>
                        <div class="col-md-6">
                            <label class="form-label">名号/封号</label>
                            <input type="text" name="name_title" class="form-control" value="{{ member.name_title if member else '' }}">
                        </div>
                        <div class="col-md-6">
                            <label class="form-label">分房/堂号</label>
                            <input type="text" name="branch_family_hall" class="form-control" value="{{ member.branch_family_hall if member else '' }}">
                        </div>
                        <div class="col-md-6">
                            <label class="form-label">聚居地</label>
                            <input type="text" name="cluster_place" class="form-control" value="{{ member.cluster_place if member else '' }}">
                        </div>
                    </div>

                    <div class="section-title">状态与联系</div>
                    <div class="row g-3">
                        <div class="col-md-4">
                            <label class="form-label">是否过世</label>
                            <select name="is_pass_away" class="form-select">
                                <option value="0" {{ 'selected' if member and member.is_pass_away == 0 else '' }}>健在</option>
                                <option value="1" {{ 'selected' if member and member.is_pass_away == 1 else '' }}>已故</option>
                            </select>
                        </div>
                        <div class="col-md-4">
                            <label class="form-label">婚姻状况</label>
                            <select name="marital_status" class="form-select">
                                <option value="0" {{ 'selected' if member and member.marital_status == 0 else '' }}>未知</option>
                                <option value="1" {{ 'selected' if member and member.marital_status == 1 else '' }}>未婚</option>
                                <option value="2" {{ 'selected' if member and member.marital_status == 2 else '' }}>已婚</option>
                                <option value="3" {{ 'selected' if member and member.marital_status == 3 else '' }}>离异/丧偶</option>
                            </select>
                        </div>
                        <div class="col-md-4">
                            <label class="form-label">民族</label>
                            <input type="text" name="nation" class="form-control" value="{{ member.nation if member else '' }}">
                        </div>
                        <div class="col-md-6">
                            <label class="form-label">手机号</label>
                            <input type="text" name="phone" class="form-control" value="{{ member.phone if member else '' }}">
                        </div>
                        <div class="col-md-6">
                            <label class="form-label">微信号</label>
                            <input type="text" name="wechat_account" class="form-control" value="{{ member.wechat_account if member else '' }}">
                        </div>
                        <div class="col-md-12">
                            <label class="form-label">现居住址</label>
                            <input type="text" name="residential_address" class="form-control" value="{{ member.residential_address if member else '' }}">
                        </div>
                    </div>

                    <div class="section-title">个人履历</div>
                    <div class="row g-3">
                        <div class="col-md-6">
                            <label class="form-label">职业</label>
                            <textarea name="occupation" class="form-control" rows="2">{{ member.occupation if member else '' }}</textarea>
                        </div>
                        <div class="col-md-6">
                            <label class="form-label">教育背景</label>
                            <textarea name="educational" class="form-control" rows="2">{{ member.educational if member else '' }}</textarea>
                        </div>
                        <div class="col-md-12">
                            <label class="form-label">标签</label>
                            <input type="text" name="tags" class="form-control" placeholder="例如：抗战老兵, 教师 (用逗号分隔)" value="{{ member.tags if member else '' }}">
                        </div>
                        <div class="col-md-12">
                            <label class="form-label">人员备注</label>
                            <textarea name="notes" class="form-control" rows="3">{{ member.notes if member else '' }}</textarea>
                        </div>
                        <div class="col-md-12">
                            <label class="form-label">个人成就</label>
                            <textarea name="personal_achievements" class="form-control" rows="3">{{ member.personal_achievements if member else '' }}</textarea>
                        </div>
                    </div>

                    <div class="d-grid gap-2 mt-5 mb-5">
                        <button type="submit" class="btn btn-success btn-lg">
                            <i class="bi bi-check-circle me-1"></i> {{ '保存修改' if member else '确认录入' }}
                        </button>
                    </div>
                </form>
            </div>
        </div>
    </div>

    
    <!-- AI 推理日志及结果面板 -->
    <div id="aiLogPanel" class="position-fixed bottom-0 end-0 p-3 bg-dark text-white shadow" 
         style="display: none; width: 450px; max-height: 85vh; border-radius: 8px 0 0 0; z-index: 1050; opacity: 0.95; overflow-y: auto;">
        <div class="d-flex justify-content-between align-items-center mb-2 border-bottom border-secondary pb-2 sticky-top bg-dark pt-1">
            <span class="fw-bold"><i class="bi bi-robot"></i> AI 识别助手</span>
            <button class="btn btn-sm btn-outline-light py-0" onclick="closeAiLog()">×</button>
        </div>
        
        <!-- 推理过程 -->
        <div class="mb-3">
             <button class="btn btn-sm btn-link text-decoration-none text-light p-0 mb-1 d-flex align-items-center" type="button" data-bs-toggle="collapse" data-bs-target="#collapseReasoning">
                 <i class="bi bi-cpu me-1"></i> 推理过程 <span class="badge bg-secondary ms-2" id="reasoningStatus">进行中...</span>
             </button>
             <div class="collapse show" id="collapseReasoning">
                 <pre id="aiLogContent" class="text-success small mb-0 p-2 bg-black rounded border border-secondary" style="max-height: 200px; overflow-y: auto; white-space: pre-wrap; font-family: monospace; font-size: 0.8rem;"></pre>
             </div>
        </div>

        <!-- 当前选中详情 -->
        <div id="aiCurrentDetail" class="mb-3 p-2 bg-secondary bg-opacity-25 rounded border border-info" style="display:none;">
            <div class="d-flex justify-content-between align-items-center mb-2 border-bottom border-secondary pb-1">
                <strong class="text-info"><i class="bi bi-info-circle"></i> 当前填充详情</strong>
                <button class="btn btn-sm btn-link text-muted py-0 text-decoration-none" onclick="document.getElementById('aiCurrentDetail').style.display='none'">×</button>
            </div>
            <div id="aiDetailContent" class="small text-light" style="word-break: break-all; max-height: 200px; overflow-y: auto;"></div>
        </div>

        <!-- 识别结果列表 -->
        <div id="aiResultSection" style="display: none;">
            <div class="d-flex justify-content-between align-items-center mb-2">
                <h6 class="mb-0 text-info"><i class="bi bi-check-circle"></i> 识别结果 (<span id="resultCount">0</span>)</h6>
                <span class="small text-muted">点击下方条目填充</span>
            </div>
            <div id="aiResultList" class="d-flex flex-column gap-2">
                <!-- 结果项将动态插入 -->
            </div>
        </div>
    </div>

    <!-- 右侧：图片参考 -->
    <div class="image-panel">
        <div class="page-nav">
            <label class="fw-bold">扫描件参考:</label>
            <button id="aiBtn" onclick="recognizeImage()" class="btn btn-sm btn-info text-white ms-2 me-2">
                <i class="bi bi-magic"></i> AI 识别
            </button>
            <input type="number" id="pageInput" class="form-control form-control-sm" style="width: 70px;" placeholder="页码">
            <button onclick="gotoPage()" class="btn btn-sm btn-primary">跳转</button>
            <div class="ms-auto small text-muted">
                当前: <span id="currentPage">1</span> / <span id="totalPages">{{ images|length }}</span>
            </div>
        </div>
        <div class="image-toolbar rounded-top">
            <div class="btn-group btn-group-sm">
                <button type="button" class="btn btn-outline-secondary" onclick="rotateImage(-90)" title="左旋90°"><i class="bi bi-arrow-counterclockwise"></i></button>
                <button type="button" class="btn btn-outline-secondary" onclick="rotateImage(90)" title="右旋90°"><i class="bi bi-arrow-clockwise"></i></button>
            </div>
            <div class="filter-controls border-start border-end px-2 mx-1">
                <i class="bi bi-brightness-high" title="亮度"></i>
                <input type="range" min="50" max="150" value="100" oninput="updateImageFilter()" id="brightnessRange">
                <i class="bi bi-circle-half ms-2" title="对比度"></i>
                <input type="range" min="50" max="200" value="100" oninput="updateImageFilter()" id="contrastRange">
                <button class="btn btn-link btn-sm text-decoration-none py-0" onclick="resetFilters()">重置</button>
            </div>
            <div class="form-check form-switch ms-auto mb-0" title="开启后鼠标悬停图片可局部放大">
                <input class="form-check-input" type="checkbox" id="magnifierSwitch">
                <label class="form-check-label small" for="magnifierSwitch">🔍 放大镜</label>
            </div>
        </div>
        <div class="image-viewer shadow-inner" id="viewer">
            <div id="magnifier" class="magnifier-glass"></div>
            <div id="imageWrapper" class="image-wrapper">
                {% if images %}
                    <img id="refImage" src="{{ images[0].oss_url }}" alt="家谱图片" draggable="false">
                {% else %}
                    <div class="mt-5 text-muted">
                        <i class="bi bi-image fs-1 d-block mb-2"></i>
                        暂无上传的家谱图片
                    </div>
                {% endif %}
            </div>
        </div>
        <div class="mt-2 d-flex justify-content-between">
            <button onclick="prevImage()" class="btn btn-sm btn-outline-secondary">上一张</button>
            <button onclick="nextImage()" class="btn btn-sm btn-outline-secondary">下一张</button>
        </div>
    </div>
</div>
{% endblock %}

{% block extra_js %}
<script>
    function toggleBirthdayUnknown() {
        const cb = document.getElementById('birthdayUnknown');
        const input = document.querySelector('input[name="birthday"]');
        if (!cb || !input) return;
        
        if (cb.checked) {
            input.value = '';
            input.disabled = true;
            input.required = false;
            input.classList.remove('is-invalid');
            const fb = document.getElementById('ageFeedback');
            if(fb) fb.textContent = '';
        } else {
            input.disabled = false;
            input.required = true;
        }
    }

    function validateAge() {
        const cb = document.getElementById('birthdayUnknown');
        if (cb && cb.checked) return;

        const birthdayInput = document.querySelector('input[name="birthday"]');
        const relatedSelect = document.querySelector('select[name="related_mid"]');
        const relationType = document.querySelector('select[name="relation_type"]');
        const feedback = document.getElementById('ageFeedback');
        
        if (!birthdayInput.value || !relatedSelect.value) {
            birthdayInput.classList.remove('is-invalid');
            return;
        }
        
        // Only check for Parent-Child relations (1: Father, 2: Mother)
        if (relationType.value !== '1' && relationType.value !== '2') return;
        
        // We need the parent's birthday. This is tricky as we only have the ID.
        // Option 1: Store parent birthdays in the select option dataset (easiest)
        // Option 2: Async fetch.
        
        const selectedOption = relatedSelect.options[relatedSelect.selectedIndex];
        const parentBirthdayTs = parseInt(selectedOption.dataset.birthday || '0');
        
        if (parentBirthdayTs > 0) {
            const childBirthday = new Date(birthdayInput.value).getTime() / 1000;
            if (childBirthday < parentBirthdayTs) {
                birthdayInput.classList.add('is-invalid');
                feedback.textContent = '警告：子女出生日期早于父母，请核对！';
            } else if (childBirthday - parentBirthdayTs < 12 * 365 * 24 * 3600) {
                 // Warning if age gap < 12 years
                 birthdayInput.classList.add('is-invalid');
                 feedback.textContent = '警告：父母与子女年龄差小于12岁，请核对！';
            } else {
                birthdayInput.classList.remove('is-invalid');
            }
        }
    }

    // Call validation when relation changes too
    document.addEventListener('DOMContentLoaded', () => {
        const relatedSelect = document.querySelector('select[name="related_mid"]');
        if (relatedSelect) relatedSelect.addEventListener('change', validateAge);
        
        // Initialize birthday unknown state
        toggleBirthdayUnknown();
    });

    const images = [
        {% for img in images %}
        { 
            id: {{ img.id }},
            url: "{{ img.oss_url }}", 
            page: {{ img.page_number or 0 }},
            ai_status: {{ img.ai_status or 0 }},
            ai_content: {{ img.ai_content | tojson | safe if img.ai_content else 'null' }}
        },
        {% endfor %}
    ];
    let currentIndex = 0;
    let currentParsedPeople = [];
    
    // Image State
    let imgRotation = 0;
    let imgBrightness = 100;
    let imgContrast = 100;
    
    // Dragging State
    let isDragging = false;
    let hasDragged = false;
    let startX = 0, startY = 0;
    let currentX = 0, currentY = 0; // Relative to center (offsets)

    // Zoom State
    let isZoomedIn = false;
    const ZOOM_LEVEL = 2.0;

    // Magnifier Logic
    const viewer = document.getElementById('viewer');
    const magnifier = document.getElementById('magnifier');
    const magnifierSwitch = document.getElementById('magnifierSwitch');
    const imageWrapper = document.getElementById('imageWrapper');
    
    // Initialize Dragging and Zooming
    if (imageWrapper) {
        // Center initial position
        imageWrapper.style.left = '50%';
        imageWrapper.style.top = '50%';
        
        viewer.style.cursor = 'zoom-in';

        viewer.addEventListener('mousedown', (e) => {
            if (e.target.closest('.image-toolbar') || e.target.closest('.magnifier-glass')) return;
            isDragging = true;
            hasDragged = false;
            startX = e.clientX;
            startY = e.clientY;
            
            viewer.style.cursor = 'grabbing';
            e.preventDefault(); // Prevent text selection
        });
        
        window.addEventListener('mousemove', (e) => {
            if (!isDragging) return;
            
            const dx = e.clientX - startX;
            const dy = e.clientY - startY;
            
            // Threshold to consider it a drag
            if (Math.abs(dx) > 2 || Math.abs(dy) > 2) {
                hasDragged = true;
            }

            currentX += dx;
            currentY += dy;
            
            startX = e.clientX;
            startY = e.clientY;
            
            updateImageTransform();
        });
        
        window.addEventListener('mouseup', (e) => {
            if (isDragging) {
                isDragging = false;
                viewer.style.cursor = isZoomedIn ? 'grab' : 'zoom-in';
                
                // If it was a click (not a drag) and clicked inside the viewer
                if (!hasDragged && viewer.contains(e.target)) {
                    toggleZoom();
                }
            }
        });
    }

    function toggleZoom() {
        isZoomedIn = !isZoomedIn;
        if (!isZoomedIn) {
            // Reset position when zooming out to center
            currentX = 0;
            currentY = 0;
        }
        updateImageTransform();
        // Update cursor immediately
        viewer.style.cursor = isZoomedIn ? 'grab' : 'zoom-in';
    }
    
    viewer.addEventListener('mousemove', function(e) {
        if (!magnifierSwitch.checked) {
            magnifier.style.display = 'none';
            return;
        }
        
        if (isDragging) {
             magnifier.style.display = 'none';
             return;
        }
        
        const img = document.getElementById('refImage');
        if (!img) return;

        // Calculate position relative to the image
        const rect = img.getBoundingClientRect();
        const x = e.clientX - rect.left;
        const y = e.clientY - rect.top;
        
        // Only show if inside image rect (approximate for rotated)
        if (x < 0 || x > rect.width || y < 0 || y > rect.height) {
            magnifier.style.display = 'none';
            return;
        }

        magnifier.style.display = 'block';
        
        // Position the glass near mouse
        const glassOffset = 20;
        const viewerRect = viewer.getBoundingClientRect();
        magnifier.style.left = (e.clientX - viewerRect.left + glassOffset) + 'px';
        magnifier.style.top = (e.clientY - viewerRect.top + glassOffset) + 'px';
        
        // Background logic (Zoom 2x)
        const zoom = 2.5;
        magnifier.style.backgroundImage = `url('${img.src}')`;
        magnifier.style.backgroundSize = `${rect.width * zoom}px ${rect.height * zoom}px`;
        
        // Simple version (imperfect for rotation)
        magnifier.style.backgroundPosition = `-${x * zoom - 75}px -${y * zoom - 75}px`; 
    });

    // Image Manipulation
    function rotateImage(deg) {
        imgRotation = (imgRotation + deg) % 360;
        updateImageTransform();
    }
    
    function updateImageFilter() {
        imgBrightness = document.getElementById('brightnessRange').value;
        imgContrast = document.getElementById('contrastRange').value;
        applyImageFilters();
    }
    
    function resetFilters() {
        imgRotation = 0;
        imgBrightness = 100;
        imgContrast = 100;
        currentX = 0;
        currentY = 0;
        isZoomedIn = false;
        
        document.getElementById('brightnessRange').value = 100;
        document.getElementById('contrastRange').value = 100;
        
        updateImageTransform();
        applyImageFilters();
    }
    
    function updateImageTransform() {
        const wrapper = document.getElementById('imageWrapper');
        if (wrapper) {
            const scale = isZoomedIn ? ZOOM_LEVEL : 1;
            wrapper.style.transform = `translate(calc(-50% + ${currentX}px), calc(-50% + ${currentY}px)) rotate(${imgRotation}deg) scale(${scale})`;
            
            // Adjust cursor based on state
            if (!isDragging) {
                viewer.style.cursor = isZoomedIn ? 'grab' : 'zoom-in';
            }
        }
    }
    
    function applyImageFilters() {
        const img = document.getElementById('refImage');
        if (img) {
            img.style.filter = `brightness(${imgBrightness}%) contrast(${imgContrast}%)`;
        }
    }
    
    // Reuse applyImageStyles as alias for compatibility if called elsewhere
    function applyImageStyles() {
        updateImageTransform();
        applyImageFilters();
    }

    const fieldMapping = {
        name: '姓名（繁体）',
        simplified_name: '姓名（简体）',
        sex: '性别',
        birthday: '出生日期',
        father_name: '父亲姓名',
        spouse_name: '配偶姓名',
        generation: '堂内排行(代数)',
        name_word: '字辈',
        education: '学历/功名',
        title: '官职/称号',
        death_date: '逝世日期',
        note: '备注'
    };

    // --- Keyboard Shortcuts ---
    document.addEventListener('keydown', (e) => {
        // Ctrl/Cmd + Enter: Save
        if ((e.ctrlKey || e.metaKey) && e.key === 'Enter') {
            e.preventDefault();
            const submitBtn = document.querySelector('form button[type="submit"]');
            if (submitBtn && !submitBtn.disabled) {
                submitBtn.click(); // Trigger form submit listener
            }
        }
        
        // Ctrl/Cmd + Right Arrow: Next Image
        if ((e.ctrlKey || e.metaKey) && e.key === 'ArrowRight') {
            e.preventDefault();
            nextImage();
        }
        
        // Ctrl/Cmd + Left Arrow: Prev Image
        if ((e.ctrlKey || e.metaKey) && e.key === 'ArrowLeft') {
            e.preventDefault();
            prevImage();
        }
        
        // Alt + 1: Auto Fill First person in list
        if (e.altKey && e.key === '1') {
            e.preventDefault();
            // Try to find the first "fill" button that is not disabled/success
            const firstBtn = document.querySelector('button[id^="btn-fill-"]:not(.btn-success)');
            if (firstBtn) firstBtn.click();
        }
    });

    // --- AJAX Form Submission ---
    document.addEventListener('DOMContentLoaded', () => {
        const form = document.querySelector('form');
        form.addEventListener('submit', async (e) => {
            e.preventDefault();
            
            // Collect form data
            const formData = new FormData(form);
            
            // Visual feedback on button
            const submitBtn = form.querySelector('button[type="submit"]');
            const originalBtnHtml = submitBtn.innerHTML;
            submitBtn.disabled = true;
            submitBtn.innerHTML = '<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span> 保存中...';
            
            try {
                // Use form.action to support both add and edit URLs
                const targetUrl = form.action || window.location.href;
                const response = await fetch(targetUrl, {
                    method: 'POST',
                    body: formData,
                    headers: {
                        'X-Requested-With': 'XMLHttpRequest'
                    }
                });
                
                const result = await response.json();
                
                if (result.success) {
                    // Success!
                    // 1. Show a toast or small alert
                    const toast = document.createElement('div');
                    toast.className = 'position-fixed bottom-0 start-50 translate-middle-x mb-4 p-3 bg-success text-white rounded shadow';
                    toast.style.zIndex = '2000';
                    toast.innerHTML = `<i class="bi bi-check-circle me-2"></i> ${result.message}`;
                    document.body.appendChild(toast);
                    setTimeout(() => toast.remove(), 3000);
                    
                    // 2. Mark the AI list item as "Saved" if applicable
                    if (window.lastFilledIndex !== undefined) {
                        const btn = document.getElementById(`btn-fill-${window.lastFilledIndex}`);
                        if (btn) {
                            btn.className = 'btn btn-sm btn-success text-white ms-2 disabled';
                            btn.innerHTML = '<i class="bi bi-check-lg"></i> 已录入';
                            btn.onclick = null;
                        }
                        
                        // Update local data state so it persists if we switch images/filters
                        if (currentParsedPeople[window.lastFilledIndex]) {
                            currentParsedPeople[window.lastFilledIndex].is_imported = true;
                            currentParsedPeople[window.lastFilledIndex].imported_member_id = result.member_id;
                            
                            // Sync back to images array to persist across image switching
                            if (images[currentIndex]) {
                                images[currentIndex].ai_content = currentParsedPeople;
                            }
                        }
                    }
                    
                    // 3. Clear form (reset to defaults) or keep some fields?
                    // Usually for genealogy, Surname/Generation might be same, but let's clear for safety
                    // Resetting form but keeping "related_mid" might be useful for siblings? 
                    // For now, simple reset.
                    
                    // --- Update Local Matches before resetting form ---
                    // If we just saved a person, check if this person is the father/spouse of anyone else in the list
                    // and update their matches so 'fillForm' will work for them.
                    
                    const savedName = formData.get('name'); // Traditional (Raw)
                    const savedSimplifiedName = formData.get('simplified_name'); // Simplified (Cleaned)
                    const savedId = result.member_id;
                    const savedSex = formData.get('sex'); // 1: Male, 2: Female
                    
                    if (savedId) {
                        currentParsedPeople.forEach(p => {
                            if (!p.matches) p.matches = {};
                            
                            // Check Father Match
                            // Try matching against Simplified Name (p.father_name is Simplified Cleaned)
                            // Or fallback to savedName if p.father_name happened to be Traditional (rare but possible)
                            if (p.father_name && (p.father_name === savedSimplifiedName || p.father_name === savedName)) {
                                // Assume simple match logic here (usually father is male)
                                if (savedSex === '1') {
                                    if (!p.matches.father) p.matches.father = [];
                                    // Add to matches if not exists
                                    if (!p.matches.father.find(m => m.id === savedId)) {
                                        p.matches.father.push({ id: savedId, name: savedName, sex: 1 }); // Mock DB object
                                    }
                                }
                            }
                            
                            // Check Spouse Match
                            if (p.spouse_name && (p.spouse_name === savedSimplifiedName || p.spouse_name === savedName)) {
                                // Spouse logic...
                                if (!p.matches.spouse) p.matches.spouse = [];
                                if (!p.matches.spouse.find(m => m.id === savedId)) {
                                    p.matches.spouse.push({ id: savedId, name: savedName, sex: parseInt(savedSex) });
                                }
                            }
                        });
                        
                        // Also, we need to add this new member to the <select> options for future manual selection!
                        // This is tricky because the select is rendered by Jinja2.
                        // We can append an option via JS.
                        const relatedSelect = document.querySelector('select[name="related_mid"]');
                        if (relatedSelect) {
                            const newOption = document.createElement('option');
                            newOption.value = savedId;
                            newOption.textContent = `${savedName} (ID: ${savedId})`;
                            // Add birthday data if available for validation
                            newOption.dataset.birthday = new Date(formData.get('birthday')).getTime() / 1000;
                            relatedSelect.add(newOption); // Add to end
                        }
                    }
                    // --- End Local Match Update ---

                    form.reset();
                    // Clear hidden/custom fields if any manually
                    form.querySelector('[name="name_word_generation"]').value = ''; 
                    form.querySelector('[name="personal_achievements"]').value = '';
                    form.querySelector('[name="notes"]').value = '';
                    form.querySelector('[name="tags"]').value = '';
                    form.querySelector('[name="family_rank"]').value = '';
                    
                    // Close detail panel
                    document.getElementById('aiCurrentDetail').style.display = 'none';

                    // 4. Auto-Next Logic
                    // Find the next available person in the list to fill
                    if (window.lastFilledIndex !== undefined) {
                        const nextIndex = window.lastFilledIndex + 1;
                        if (currentParsedPeople[nextIndex]) {
                            // Automatically fill the next one!
                            fillForm(nextIndex);
                            
                            // Scroll list to show the new active item if needed
                            const btn = document.getElementById(`btn-fill-${nextIndex}`);
                            if(btn) btn.scrollIntoView({ behavior: 'smooth', block: 'center' });
                        }
                    }

                } else {
                    alert('保存失败: ' + result.message);
                }
            } catch (error) {
                console.error('Error submitting form:', error);
                alert('网络或服务器错误，请稍后重试');
            } finally {
                submitBtn.disabled = false;
                submitBtn.innerHTML = originalBtnHtml;
            }
        });
    });

    // --- End AJAX Form Submission ---

    function updateDisplay() {
        if (images.length > 0) {
            const img = images[currentIndex];
            document.getElementById('refImage').src = img.url;
            document.getElementById('currentPage').innerText = currentIndex + 1;
            
            // Reset image state on switch
            resetFilters();
            
            // AI Button Logic
            const aiBtn = document.getElementById('aiBtn');
            const aiPanel = document.getElementById('aiLogPanel');
            const resultList = document.getElementById('aiResultList');
            const resultCount = document.getElementById('resultCount');
            
            // Hide panel when switching images to avoid confusion
            if (aiPanel) aiPanel.style.display = 'none';
            // Clear current data
            currentParsedPeople = []; 
            if (resultCount) resultCount.innerText = '0';
            if (resultList) resultList.innerHTML = ''; 

            if (img.ai_status === 2 && img.ai_content) {
                // Determine content
                let content = img.ai_content;
                // Parse if string (it might be a string if double encoded or stored as JSON string in DB)
                if (typeof content === 'string') {
                    try { content = JSON.parse(content); } catch(e) { content = []; }
                }
                if (!Array.isArray(content) && content) content = [content];
                
                if (content && content.length > 0) {
                    // Update Button to "View Results"
                    aiBtn.innerHTML = '<i class="bi bi-list-check"></i> 查看解析结果';
                    aiBtn.className = 'btn btn-sm btn-success text-white ms-2 me-2';
                    aiBtn.onclick = function() {
                        // Show panel with loading
                        if (aiPanel) aiPanel.style.display = 'block';
                        if (resultList) resultList.innerHTML = '<div class="text-center p-3"><div class="spinner-border text-primary" role="status"></div></div>';
                        
                        // Process (small delay to allow UI update)
                        setTimeout(() => processAiData(content), 10);
                    };
                    return; // Done
                }
            } 
            
            // Default: Reset to "AI Recognition"
            aiBtn.innerHTML = '<i class="bi bi-magic"></i> AI 识别';
            aiBtn.className = 'btn btn-sm btn-info text-white ms-2 me-2';
            aiBtn.onclick = recognizeImage;
        }
    }

    function nextImage() {
        if (currentIndex < images.length - 1) {
            currentIndex++;
            updateDisplay();
        }
    }

    function prevImage() {
        if (currentIndex > 0) {
            currentIndex--;
            updateDisplay();
        }
    }

    function gotoPage() {
        const val = document.getElementById('pageInput').value;
        if (!val) return;
        const page = parseInt(val);
        const index = images.findIndex(img => img.page === page);
        if (index !== -1) {
            currentIndex = index;
            updateDisplay();
        } else {
            alert('未找到该页码对应的图片');
        }
    }

    function closeAiLog() {
        document.getElementById('aiLogPanel').style.display = 'none';
    }

    function toggleAiPanel() {
        const panel = document.getElementById('aiLogPanel');
        if (panel.style.display === 'none') {
            panel.style.display = 'block';
        } else {
            panel.style.display = 'none';
        }
    }

    function updateAiButtonState(hasResults) {
        const btn = document.getElementById('aiBtn');
        if (!btn) return;

        if (hasResults) {
            btn.innerHTML = '<i class="bi bi-list-check"></i> 查看识别结果';
            btn.onclick = toggleAiPanel;
            btn.classList.remove('btn-info');
            btn.classList.add('btn-success');
        } else {
            // Revert state if needed (usually on new image load if we clear data)
            btn.innerHTML = '<i class="bi bi-magic"></i> AI 识别';
            btn.onclick = recognizeImage;
            btn.classList.remove('btn-success');
            btn.classList.add('btn-info');
        }
    }

    function fillForm(index) {
        window.lastFilledIndex = index;
        const person = currentParsedPeople[index];
        if (!person) return;
        
        const form = document.querySelector('form');
        form.reset(); // Clear previous data first
        
        // Set Source Index
        const sourceIndexInput = form.querySelector('[name="source_index"]');
        if (sourceIndexInput) sourceIndexInput.value = index;

        // 1. 姓名
        if (person.name) form.querySelector('[name="name"]').value = person.name;
        if (person.simplified_name) {
            const snInput = form.querySelector('[name="simplified_name"]');
            if (snInput) snInput.value = person.simplified_name;
        } else {
             // Fallback: if no simplified_name explicitly, generate it
             if (person.name) {
                 const snInput = form.querySelector('[name="simplified_name"]');
                 if (snInput) snInput.value = cleanName(person.name);
             }
        }
        
        // 2. 性别
        if (person.sex) {
            const sexSelect = form.querySelector('[name="sex"]');
            if (person.sex.includes('女')) sexSelect.value = '2';
            else if (person.sex.includes('男')) sexSelect.value = '1';
        }
        
        // 3. 生日 & 自动推断过世
        // Reset unknown toggle first
        const birthdayUnknownCb = document.getElementById('birthdayUnknown');
        if (birthdayUnknownCb) {
             birthdayUnknownCb.checked = false;
             toggleBirthdayUnknown();
        }

        if (person.birthday) {
            let dateVal = person.birthday;
            // 尝试标准化
            const dateMatch = dateVal.match(/(\d{4})[-/年](\d{1,2})[-/月](\d{1,2})/);
            if (dateMatch) {
                const y = dateMatch[1];
                const m = dateMatch[2].padStart(2, '0');
                const d = dateMatch[3].padStart(2, '0');
                dateVal = `${y}-${m}-${d}`;
                
                // Auto "Is Deceased" Logic (e.g. older than 100 years from now)
                const birthYear = parseInt(y);
                const currentYear = new Date().getFullYear();
                if (currentYear - birthYear > 100) {
                    const passAwaySelect = form.querySelector('[name="is_pass_away"]');
                    if (passAwaySelect) passAwaySelect.value = '1';
                }
            }
            // 只有当日期格式正确时才填充，否则不填或者留给用户
            if (/^\d{4}-\d{2}-\d{2}$/.test(dateVal)) {
                form.querySelector('[name="birthday"]').value = dateVal;
            }
        }

        // 4. 代数 -> 堂内排行
        if (person.generation) {
            const genMatch = person.generation.match(/\d+/);
            // 这里将 AI 解析的 'generation' 填入 'family_rank' (堂内排行)
            // 'name_word_generation' (世系世代) 保持为空
            form.querySelector('[name="family_rank"]').value = person.generation; 
        }

        // 4.5 字辈 (name_word)
        let zibei = person.name_word;
        if (!zibei && person.name) {
             // Heuristic: If name starts with "留" and is 3 chars long (e.g. 留学勤), Zibei is index 1.
             // If name starts with "留" and is > 3 chars, we can't be sure, but index 1 is a good guess for generation char.
             // "留学公" -> "留" + "学" + "公". Zibei "学".
             // "留学勤" -> "留" + "学" + "勤". Zibei "学".
             
             // Let's use a safe heuristic: if name starts with '留' and length >= 3
             if (person.name.startsWith('留') && person.name.length >= 3) {
                 zibei = person.name.charAt(1);
             }
        }
        if (zibei) {
            form.querySelector('[name="name_word"]').value = zibei;
            person.name_word = zibei; // Update data object for display
        }

        // 5. 其他信息
        if (person.education) form.querySelector('[name="educational"]').value = person.education;
        if (person.title) form.querySelector('[name="occupation"]').value = person.title;
        
        // 个人成就/备注字段追加信息
        let extraInfo = [];
        if (person.father_name) extraInfo.push(`父亲: ${person.father_name}`);
        if (person.spouse_name) extraInfo.push(`配偶: ${person.spouse_name}`);
        
        // 将亲属关系存入 'notes' (人员备注) 字段
        const notesField = form.querySelector('[name="notes"]');
        const currentNotes = notesField.value;
        const newInfo = extraInfo.join('; ');
        
        if (newInfo && !currentNotes.includes(newInfo)) {
             notesField.value = currentNotes ? (currentNotes + '\n' + newInfo) : newInfo;
        }

        // --- Auto-Linking Logic ---
        if (person.matches) {
            // Priority: Father > Spouse (Configurable?)
            // For now, if father matches, select father.
            if (person.matches.father && person.matches.father.length > 0) {
                // Pick the first one for now (could show UI to choose if multiple)
                const father = person.matches.father[0];
                const relSelect = form.querySelector('[name="related_mid"]');
                const relTypeSelect = form.querySelector('[name="relation_type"]');
                
                if (relSelect && relTypeSelect) {
                    relSelect.value = father.id;
                    relTypeSelect.value = '1'; // 父子
                    // Trigger change event if needed by other logic (not needed here yet)
                }
            } else if (person.matches.spouse && person.matches.spouse.length > 0) {
                const spouse = person.matches.spouse[0];
                const relSelect = form.querySelector('[name="related_mid"]');
                const relTypeSelect = form.querySelector('[name="relation_type"]');
                
                if (relSelect && relTypeSelect) {
                    relSelect.value = spouse.id;
                    relTypeSelect.value = '10'; // 夫妻
                }
            }
        }
        
        // --- Show Details Panel ---
        const detailContainer = document.getElementById('aiCurrentDetail');
        const detailContent = document.getElementById('aiDetailContent');
        
        let html = '<ul class="list-unstyled mb-0 font-monospace" style="font-size: 0.85rem;">';
        
        const getLabel = (k) => fieldMapping[k] || (k === 'children' ? '子女' : k);

        // 遍历属性显示
        for (const key in person) {
             // 隐藏内部属性
             if (key.startsWith('_')) continue;
             
             let val = person[key];
             const label = getLabel(key);

             // 特殊处理 children
             if (key === 'children') {
                 if (Array.isArray(val) && val.length > 0) {
                     let childrenHtml = '<div class="d-flex flex-wrap gap-1 mt-1">';
                     val.forEach(child => {
                         // 使用 child._originalIndex 进行跳转填充
                         childrenHtml += `<button class="btn btn-sm btn-outline-info py-0 px-2" style="font-size: 0.75rem;" onclick="fillForm(${child._originalIndex})">${child.name || '未知'}</button>`;
                     });
                     childrenHtml += '</div>';
                     html += `<li class="mb-1"><span class="text-info opacity-75">${label}:</span> ${childrenHtml}</li>`;
                 }
                 continue;
             }
             
             // 默认显示
             if (!val || val === '') val = '-';
             html += `<li class="mb-1"><span class="text-info opacity-75">${label}:</span> <span class="text-white ms-1">${val}</span></li>`;
        }
        html += '</ul>';
        
        detailContent.innerHTML = html;
        detailContainer.style.display = 'block';
        
        // Visual feedback
        const btn = document.getElementById(`btn-fill-${index}`);
        if(btn) {
            const originalHtml = btn.innerHTML;
            btn.innerHTML = '<i class="bi bi-check"></i> 已填';
            btn.classList.remove('btn-outline-info');
            btn.classList.add('btn-info', 'text-white');
            setTimeout(() => {
                btn.innerHTML = originalHtml;
                btn.classList.add('btn-outline-info');
                btn.classList.remove('btn-info', 'text-white');
            }, 1000);
        }
    }

    // --- Pre-fill Logic from Backend (Async AI Result) ---
    const prefilledContent = {{ prefilled_content | tojson | safe if prefilled_content else 'null' }};
    const sourceOssUrl = "{{ source_oss_url if source_oss_url else '' }}";
    const sourceRecordId = "{{ source_record_id if source_record_id else '' }}";

    if (prefilledContent && sourceOssUrl) {
        // We have prefilled content from DB, simulate "Recognize Image" success
        document.addEventListener('DOMContentLoaded', async () => {
            // Wait a bit for UI to settle
            setTimeout(async () => {
                // Find image index
                const imgIndex = images.findIndex(img => img.url === sourceOssUrl);
                if (imgIndex !== -1) {
                    currentIndex = imgIndex;
                    updateDisplay();
                }
                
                // Parse and display results
                try {
                    let data = prefilledContent;
                    if (typeof data === 'string') {
                        try {
                            data = JSON.parse(data);
                        } catch(e) {
                            console.error("Prefilled content parse error", e);
                            return;
                        }
                    }
                    
                    if (!Array.isArray(data)) data = [data];
                    
                    await processAiData(data);
                    
                    // Open the log panel to show results
                    const aiPanel = document.getElementById('aiLogPanel');
                    if (aiPanel) aiPanel.style.display = 'block';
                    
                    const status = document.getElementById('reasoningStatus');
                    if(status) {
                        status.textContent = '已加载历史解析';
                        status.className = 'badge bg-success ms-2';
                    }
                    
                    const logContent = document.getElementById('aiLogContent');
                    if(logContent) logContent.textContent = "已加载历史 AI 解析记录。";
                    
                } catch (e) {
                    console.error("Error processing prefilled content", e);
                }
            }, 500);
        });
    } else {
        // No prefilled content, initialize display for the first image
        document.addEventListener('DOMContentLoaded', () => {
            updateDisplay();
        });
    }
    
    // --- Name Cleaning Logic (Matching Backend) ---
    // 仅做繁 -> 简转换，不动姓氏/“公”处理，用于配偶等非留氏族人
    function manualSimplify(text) {
        if (!text) return text;
        text = text.trim();
        const mapping = {
            '學': '学', '國': '国', '萬': '万', '寶': '宝', '興': '兴', 
            '華': '华', '會': '会', '葉': '叶', '藝': '艺', '號': '号',
            '處': '处', '見': '见', '視': '视', '言': '言', '語': '语',
            '貝': '贝', '車': '车', '長': '长', '門': '门', '韋': '韦',
            '頁': '页', '風': '风', '飛': '飞', '食': '食', '馬': '马',
            '魚': '鱼', '鳥': '鸟', '麥': '麦', '黃': '黄', '齊': '齐',
            '齒': '齿', '龍': '龙', '龜': '龟', '壽': '寿', '榮': '荣',
            '愛': '爱', '慶': '庆', '衛': '卫', '賢': '贤', '義': '义',
            '禮': '礼', '樂': '乐', '靈': '灵', '滅': '灭', '氣': '气',
            '智': '智', '信': '信', '仁': '仁', '勇': '勇', '嚴': '严',
            '劉': '刘'
        };
        let result = '';
        for (const ch of text) {
            result += mapping[ch] || ch;
        }
        return result;
    }

    // 留氏本人姓名清洗：在 manualSimplify 基础上，处理“留”姓和“公”
    function cleanName(name) {
        if (!name) return name;
        name = manualSimplify(name);

        const exceptions = ['学公', '留学公'];
        if (exceptions.includes(name)) {
            if (!name.startsWith('留')) {
                name = '留' + name;
            }
            return name;
        }
        
        // Remove '公' suffix
        if (name.endsWith('公')) {
            name = name.slice(0, -1);
        }
        
        // Ensure '留' prefix
        if (!name.startsWith('留')) {
            name = '留' + name;
        }
        
        return name;
    }

    // Extracted function to process AI data and render tree
    async function processAiData(data) {
        // Clean Names First
        data.forEach(p => {
            // Determine "Original" (Raw) and "Simplified" (Cleaned)
            let rawName = p.original_name || p.name;
            let simName = p.name; // This is the Simplified one from AI if original_name exists
            
            // Clean the Simplified Name（本人：带“留”姓规则）
            p.simplified_name = cleanName(simName);
            
            // Set the name to be the Raw Name for storage in 'name' column
            p.name = rawName;
            
            // 父亲：同族，用 cleanName（加“留”、去“公”）
            if (p.father_name) p.father_name = cleanName(p.father_name);

            // 配偶：只做繁体 -> 简体，不拼接“留”姓
            if (p.spouse_name) p.spouse_name = manualSimplify(p.spouse_name);
        });

         // Call Relation Check API
        try {
            // Send simplified_name for checking relations if available, or name?
            // The API checks against DB 'name' column.
            // Wait, DB 'name' column is now Traditional Raw.
            // But existing data in DB is Simplified Cleaned.
            // New data will be Traditional Raw in 'name', Simplified Cleaned in 'simplified_name'.
            // The check_relations API uses `WHERE name IN (...)`.
            // The AI returns `father_name` as Simplified (usually).
            // So we are checking Simplified Father Name against...
            // If DB 'name' is mixed (Old Simplified, New Traditional), this is messy.
            // But `check_relations` logic:
            // `names_to_check.add(p['father_name'])` -> Simplified.
            // `SELECT ... WHERE name IN ...`
            // If DB 'name' contains Traditional, we won't find match if we search Simplified.
            // Unless we search `simplified_name` column too?
            // I should update `check_relations` in app.py to search both `name` and `simplified_name`.
            
            const checkRes = await fetch('/manager/api/check_relations', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ people: data })
            });
            const checkResult = await checkRes.json();
            if (checkResult.success && checkResult.matches) {
                // Merge matches into data
                for (const idx in checkResult.matches) {
                    const match = checkResult.matches[idx];
                    if (data[idx]) {
                        data[idx].matches = match;
                    }
                }
            }
        } catch (e) {
            console.warn("Auto-linking failed:", e);
        }

        currentParsedPeople = data;
        document.getElementById('resultCount').innerText = data.length;
        
        // Update Button State to "View Results"
        updateAiButtonState(true);
        
        // Build Relationship Tree
        const personMap = {};
        const roots = [];
        
        // 1. Initialize map
        data.forEach((p, index) => {
            p._originalIndex = index; // Store original index for fillForm
            p.children = [];
            // Use simplified_name as key if available, otherwise name (for consistent lookup)
            const lookupKey = p.simplified_name || p.name;
            personMap[lookupKey] = p;
        });
        
        // 2. Build Hierarchy
        data.forEach(p => {
            let parentFound = false;
            if (p.father_name) {
                // Try exact match using simplified name (since father_name is usually simplified)
                let father = personMap[p.father_name];
                
                // Try loose match
                if (!father) {
                    for (const name in personMap) {
                        if (name.includes(p.father_name) || p.father_name.includes(name)) {
                            father = personMap[name];
                            break;
                        }
                    }
                }
                
                if (father && father !== p) { 
                    father.children.push(p);
                    parentFound = true;
                }
            }
            
            if (!parentFound) {
                roots.push(p);
            }
        });
        
        // 3. Recursive Render Function
        function renderNode(p, level = 0) {
            const indent = level * 20;
            let html = `
                <div class="card bg-dark border-secondary mb-1" style="margin-left: ${indent}px; background-color: #2c3034;">
                    <div class="card-body p-2 d-flex justify-content-between align-items-center">
                        <div class="text-white">
                            <div class="fw-bold">
                                ${level > 0 ? '<i class="bi bi-arrow-return-right text-secondary me-1"></i>' : ''}
                                ${p.name || '未知姓名'} 
                                <span class="badge bg-secondary text-light ms-1" style="font-size: 0.7rem">${p.sex || '-'}</span>
                            </div>
                            <div class="small text-white-50" style="font-size: 0.75rem; padding-left: ${level > 0 ? 18 : 0}px;">
                                ${p.generation ? '第'+p.generation+'世 ' : ''}
                                ${p.father_name ? '父:'+p.father_name : ''}
                            </div>
                        </div>
                        <button id="btn-fill-${p._originalIndex}" 
                                class="btn btn-sm ${p.is_imported ? 'btn-success disabled' : 'btn-outline-info'} text-nowrap ms-2" 
                                onclick="${p.is_imported ? '' : `fillForm(${p._originalIndex})`}">
                            ${p.is_imported ? '<i class="bi bi-check-lg"></i> 已录入' : '<i class="bi bi-pencil-square"></i> 填充'}
                        </button>
                    </div>
                </div>
            `;
            
            if (p.children && p.children.length > 0) {
                p.children.forEach(child => {
                    html += renderNode(child, level + 1);
                });
            }
            
            return html;
        }
        
        // Render List
        const resultList = document.getElementById('aiResultList');
        const resultSection = document.getElementById('aiResultSection');
        
        resultList.innerHTML = '';
        
        // Fix: Use data directly if root finding logic fails or returns empty but data exists
        if (roots.length === 0 && data.length > 0) {
            // Just dump everything flat if tree building fails
            data.forEach(p => resultList.innerHTML += renderNode(p, 0));
        } else {
            roots.forEach(p => {
                resultList.innerHTML += renderNode(p, 0);
            });
        }
        
        resultSection.style.display = 'block';
    }

    async function recognizeImage() {
        if (images.length === 0) {
            alert('没有可用的图片');
            return;
        }

        const currentImg = images[currentIndex];
        const btn = document.getElementById('aiBtn');
        const originalContent = btn.innerHTML;
        const logPanel = document.getElementById('aiLogPanel');
        const logContent = document.getElementById('aiLogContent');
        const resultSection = document.getElementById('aiResultSection');
        const resultList = document.getElementById('aiResultList');
        const reasoningStatus = document.getElementById('reasoningStatus');

        btn.disabled = true;
        btn.innerHTML = '<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span> 识别中...';
        
        // Reset UI
        logContent.textContent = '';
        resultList.innerHTML = '';
        resultSection.style.display = 'none';
        logPanel.style.display = 'block';
        reasoningStatus.textContent = '连接中...';
        reasoningStatus.className = 'badge bg-secondary ms-2';
        
        // Ensure reasoning panel is open
        const collapseReasoning = document.getElementById('collapseReasoning');
        if (collapseReasoning && !collapseReasoning.classList.contains('show')) {
            new bootstrap.Collapse(collapseReasoning, { show: true });
        }

        // Retry logic function
        async function fetchAndParse(url, retryCount = 0) {
            const MAX_RETRIES = 2;
            let fullText = '';
            let jsonPart = '';
            let hasJsonStarted = false;

            try {
                if (retryCount > 0) {
                    logContent.textContent = `\n[System] 解析失败，正在进行第 ${retryCount} 次重试...\n` + logContent.textContent;
                    reasoningStatus.textContent = `重试 ${retryCount}...`;
                }

                const response = await fetch('/manager/api/recognize_image', {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({ image_url: url })
                });

                if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);

                const reader = response.body.getReader();
                const decoder = new TextDecoder();
                const separator = "|||JSON_START|||";

                while (true) {
                    const { value, done } = await reader.read();
                    if (done) break;
                    
                    const chunk = decoder.decode(value, { stream: true });
                    fullText += chunk;
                    
                    // Only update display if not parsing JSON part yet or just started
                    if (!hasJsonStarted) {
                        const sepIndex = fullText.indexOf(separator);
                        if (sepIndex !== -1) {
                            hasJsonStarted = true;
                            reasoningStatus.textContent = '解析中...';
                            reasoningStatus.className = 'badge bg-info ms-2';
                            
                            // Split content for display - only once
                            const reasoningPart = fullText.substring(0, sepIndex);
                            logContent.textContent = reasoningPart;
                            
                            if (collapseReasoning) {
                                new bootstrap.Collapse(collapseReasoning, { hide: true });
                            }
                        } else {
                            // Update reasoning text
                            logContent.textContent = fullText;
                            logContent.scrollTop = logContent.scrollHeight;
                        }
                    }
                }

                // Parsing Logic
                if (hasJsonStarted) {
                     const sepIndex = fullText.indexOf(separator);
                     jsonPart = fullText.substring(sepIndex + separator.length);
                     reasoningStatus.textContent = '完成';
                     reasoningStatus.className = 'badge bg-success ms-2';
                } else {
                     // Fallback
                     jsonPart = fullText; 
                }
                
                // Clean JSON
                // 1. Try finding [...] array
                let start = jsonPart.indexOf('[');
                let end = jsonPart.lastIndexOf(']');
                
                // 2. If not found, try finding {...} object and wrap it
                let isSingleObject = false;
                if (start === -1 || end === -1 || end <= start) {
                    start = jsonPart.indexOf('{');
                    end = jsonPart.lastIndexOf('}');
                    isSingleObject = true;
                }

                if (start !== -1 && end !== -1 && end > start) {
                    jsonPart = jsonPart.substring(start, end + 1);
                } else {
                    // Try to extract any JSON-like array/object structure using regex as fallback
                    const jsonMatch = jsonPart.match(/(\[.*\]|\{.*\})/s);
                    if (jsonMatch) {
                        jsonPart = jsonMatch[0];
                        if (jsonPart.trim().startsWith('{')) isSingleObject = true;
                    } else {
                        // No valid JSON structure found
                        console.warn("No JSON brackets found in:", jsonPart);
                        throw new Error("未找到有效的 JSON 数据结构");
                    }
                }
                
                let data;
                try {
                    // Pre-clean: Remove common markdown code block markers if stuck inside
                    jsonPart = jsonPart.replace(/^```json\s*/, '').replace(/```$/, '');
                    
                    data = JSON.parse(jsonPart);
                } catch (e) {
                    // Attempt to fix common JSON errors (e.g. trailing commas, unclosed strings) - simplified
                    console.error("JSON parse error. Content:", jsonPart);
                    // Force retry on parse error
                    throw new Error("JSON 格式解析错误");
                }

                if (isSingleObject && !Array.isArray(data)) {
                    data = [data]; // Normalize to array
                } else if (!Array.isArray(data)) {
                    data = [data];
                }
                
                return data;

            } catch (error) {
                if (retryCount < MAX_RETRIES) {
                    // Wait 1s and retry
                    await new Promise(r => setTimeout(r, 1000));
                    return fetchAndParse(url, retryCount + 1);
                }
                throw error;
            }
        }

        try {
            const data = await fetchAndParse(currentImg.url);
            
            // Use shared processing function
            await processAiData(data);

            // Update local state for persistence during session
            if (images[currentIndex]) {
                images[currentIndex].ai_status = 2;
                images[currentIndex].ai_content = data; 
            }

        } catch (error) {
            console.error(error);
            // Append error to log instead of overwriting valid reasoning
            logContent.textContent += `\n\n[Error] ${error.message}`;
            alert('AI 识别过程失败，请重试。\n错误详情: ' + error.message);
        } finally {
            btn.innerHTML = originalContent;
            btn.disabled = false;
        }
    }
</script>
{% endblock %}
