#!/usr/bin/env python3
"""读取分析结果JSON，生成深色主题可视化HTML预算分析报告"""
import json
import os
from collections import defaultdict

BASE_DIR = "/data/www/files/2026-yjs-dsl"
JSON_PATH = os.path.join(BASE_DIR, "analysis_results.json")
HTML_OUTPUT = "/data/www/files/2026-yjs-dsl-2026-report.html"
SUBDIR = "2026-yjs-dsl"  # HTML与文件不在同目录，链接需加前缀

# 关键字颜色映射
KW_COLORS = {
    "网络培训": "#e74c3c",
    "培训": "#e67e22",
    "能力提升": "#f1c40f",
    "视频拍摄": "#2ecc71",
    "党员教育片": "#1abc9c",
    "课程制作": "#16a085",
    "直播": "#3498db",
    "视频": "#2980b9",
    "课件": "#9b59b6",
    "系统": "#8e44ad",
    "信息化": "#e84393",
    "网络": "#fd79a8",
    "数字": "#00cec9",
    "设备": "#6c5ce7",
    "平台": "#a29bfe",
    "维护": "#fdcb6e",
    "软件": "#ff7675",
}

# 关键字图标
KW_ICONS = {
    "网络培训": "🌐", "培训": "📚", "能力提升": "💪", "视频拍摄": "🎥",
    "党员教育片": "🎬", "课程制作": "📝", "直播": "📡", "视频": "📹",
    "课件": "📖", "系统": "⚙️", "信息化": "💻", "网络": "🔗",
    "数字": "🔢", "设备": "🖥️", "平台": "🏗️", "维护": "🔧", "软件": "💾",
}

def load_data():
    with open(JSON_PATH, 'r', encoding='utf-8') as f:
        return json.load(f)

def merge_matches(matches):
    """合并相同关键字：金额累加，位置全列出"""
    merged = defaultdict(lambda: {"keyword": "", "contents": [], "locations": [], "amount": 0.0, "count": 0})
    for m in matches:
        kw = m["keyword"]
        merged[kw]["keyword"] = kw
        merged[kw]["contents"].append(m["content"])
        merged[kw]["locations"].append(m["location"])
        merged[kw]["amount"] += m["amount"]
        merged[kw]["count"] += 1
    return list(merged.values())

def build_html(data):
    # 按市州→区县→单位类型分层
    hierarchy = defaultdict(lambda: defaultdict(lambda: defaultdict(list)))
    
    for fname, info in data.items():
        city = info["city"]
        district = info["district"]
        org_type = info["org_type"]
        for m in info["matches"]:
            m["source_file"] = fname
            hierarchy[city][district][org_type].append(m)
    
    # 汇总统计
    total_files = len(data)
    total_matches = sum(len(info["matches"]) for info in data.values())
    total_amount = sum(m["amount"] for info in data.values() for m in info["matches"])
    cities = sorted(hierarchy.keys())
    total_districts = sum(len(dists) for dists in hierarchy.values())
    
    # 关键字统计
    kw_stats = defaultdict(lambda: {"count": 0, "amount": 0.0})
    for info in data.values():
        for m in info["matches"]:
            kw_stats[m["keyword"]]["count"] += 1
            kw_stats[m["keyword"]]["amount"] += m["amount"]
    kw_stats_sorted = sorted(kw_stats.items(), key=lambda x: x[1]["count"], reverse=True)
    kws_used = len(kw_stats)
    
    # 单位类型图标
    org_icons = {
        "组织部": "📋",
        "党校": "🎓",
        "民政局": "🏥",
        "政府": "🏛️",
    }
    
    # 市州颜色
    city_colors = {
        "青海省": "#e84393",
        "西宁市": "#0984e3",
        "海东市": "#00b894",
    }
    
    html_parts = []
    
    # ===== HTML HEAD =====
    html_parts.append(f'''<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>2026年 杜书磊 负责市场区域预决算分析报告</title>
<style>
* {{ margin:0; padding:0; box-sizing:border-box; }}
body {{ 
    background: #0a0e27; color: #e0e6ed; font-family: 'Microsoft YaHei','Segoe UI',sans-serif;
    line-height: 1.6; min-height: 100vh;
}}
.container {{ max-width: 1400px; margin: 0 auto; padding: 20px; }}

/* Header */
.header {{ 
    background: linear-gradient(135deg, #1a1f3a 0%, #0d1117 100%);
    border: 1px solid #1e2a4a; border-radius: 16px; padding: 30px 40px; margin-bottom: 24px;
    text-align: center; position: relative; overflow: hidden;
}}
.header::before {{
    content: ''; position: absolute; top:0; left:0; right:0; bottom:0;
    background: radial-gradient(circle at 30% 50%, rgba(9,132,227,0.08) 0%, transparent 60%);
    background: radial-gradient(circle at 70% 50%, rgba(0,184,148,0.08) 0%, transparent 60%);
}}
.header h1 {{ font-size: 28px; color: #74b9ff; margin-bottom: 8px; position: relative; }}
.header .subtitle {{ color: #636e72; font-size: 14px; position: relative; }}
.header .date {{ color: #a4b0be; font-size: 13px; margin-top: 6px; position: relative; }}

/* Summary Cards */
.summary-grid {{ display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 16px; margin-bottom: 24px; }}
.sum-card {{
    background: linear-gradient(135deg, #151a30 0%, #0d1117 100%);
    border: 1px solid #1e2a4a; border-radius: 12px; padding: 24px; text-align: center;
    transition: transform 0.2s, box-shadow 0.2s;
}}
.sum-card:hover {{ transform: translateY(-3px); box-shadow: 0 8px 24px rgba(9,132,227,0.15); }}
.sum-card .num {{ font-size: 32px; font-weight: 700; margin: 8px 0; }}
.sum-card .label {{ color: #636e72; font-size: 13px; text-transform: uppercase; letter-spacing: 1px; }}
.sum-card .unit {{ font-size: 14px; color: #a4b0be; }}
.c1 .num {{ color: #0984e3; }} .c2 .num {{ color: #00b894; }}
.c3 .num {{ color: #e84393; }} .c4 .num {{ color: #fdcb6e; }}
.c5 .num {{ color: #a29bfe; }} .c6 .num {{ color: #ff7675; }}

/* Keyword Distribution Chart */
.chart-section {{
    background: #0d1117; border: 1px solid #1e2a4a; border-radius: 12px;
    padding: 24px; margin-bottom: 24px;
}}
.chart-section h2 {{ color: #74b9ff; font-size: 18px; margin-bottom: 16px; border-bottom: 1px solid #1e2a4a; padding-bottom: 12px; }}
.kw-bar {{ display: flex; align-items: center; margin-bottom: 8px; gap: 12px; }}
.kw-bar .kw-label {{ width: 100px; text-align: right; font-size: 13px; color: #b2bec3; flex-shrink: 0; }}
.kw-bar .kw-bar-bg {{ flex: 1; height: 24px; background: #151a30; border-radius: 6px; overflow: hidden; position: relative; }}
.kw-bar .kw-bar-fill {{ height: 100%; border-radius: 6px; display: flex; align-items: center; padding-left: 10px; font-size: 12px; color: #fff; font-weight: 600; transition: width 0.5s ease; }}
.kw-bar .kw-amount {{ width: 120px; font-size: 13px; color: #dfe6e9; flex-shrink: 0; }}

/* City Navigation */
.city-nav {{ display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 24px; justify-content: center; }}
.city-nav a {{
    display: inline-flex; align-items: center; gap: 6px; padding: 8px 20px;
    border-radius: 20px; text-decoration: none; font-size: 14px; font-weight: 500;
    transition: all 0.2s;
}}
.city-nav a:hover {{ transform: translateY(-2px); }}

/* Search */
.search-box {{
    width: 100%; padding: 12px 20px; background: #0d1117; border: 1px solid #1e2a4a;
    border-radius: 8px; color: #e0e6ed; font-size: 14px; margin-bottom: 24px;
}}
.search-box::placeholder {{ color: #636e72; }}
.search-box:focus {{ outline: none; border-color: #0984e3; }}

/* City Section */
.city-section {{
    background: #0d1117; border: 1px solid #1e2a4a; border-radius: 12px;
    margin-bottom: 16px; overflow: hidden;
}}
.city-header {{
    padding: 16px 24px; cursor: pointer; display: flex; align-items: center;
    justify-content: space-between; transition: background 0.2s;
}}
.city-header:hover {{ background: #151a30; }}
.city-header h3 {{ font-size: 18px; display: flex; align-items: center; gap: 8px; }}
.city-header .city-amount {{ font-size: 16px; font-weight: 600; }}
.city-header .toggle {{ color: #636e72; font-size: 14px; transition: transform 0.3s; }}
.city-section.open .toggle {{ transform: rotate(180deg); }}
.city-body {{ display: none; padding: 0 24px 24px; }}
.city-section.open .city-body {{ display: block; }}

/* District */
.district-block {{ margin-bottom: 20px; }}
.district-title {{ font-size: 15px; color: #a4b0be; margin: 16px 0 8px; padding-bottom: 6px; border-bottom: 1px solid #1e2a4a; }}

/* Org Block */
.org-block {{ margin-bottom: 16px; }}
.org-header {{
    display: flex; align-items: center; justify-content: space-between;
    padding: 10px 16px; background: #151a30; border-radius: 8px; margin-bottom: 8px;
}}
.org-header .org-name {{ font-size: 15px; display: flex; align-items: center; gap: 6px; }}
.org-header .org-sum {{ font-size: 14px; font-weight: 600; color: #fdcb6e; }}

/* Table */
table {{ width: 100%; border-collapse: collapse; font-size: 13px; }}
thead th {{
    background: #0a0e27; color: #636e72; text-align: left; padding: 10px 12px;
    font-weight: 500; text-transform: uppercase; font-size: 11px; letter-spacing: 0.5px;
    border-bottom: 1px solid #1e2a4a; position: sticky; top: 0;
}}
tbody tr {{ border-bottom: 1px solid #0d1117; transition: background 0.15s; }}
tbody tr:hover {{ background: #151a30; }}
tbody td {{ padding: 10px 12px; color: #dfe6e9; vertical-align: top; }}

/* Keyword Tag */
.kw-tag {{
    display: inline-flex; align-items: center; gap: 4px; padding: 3px 10px;
    border-radius: 12px; font-size: 12px; font-weight: 500; white-space: nowrap;
}}
.kw-count {{ font-size: 11px; opacity: 0.7; margin-left: 4px; }}

/* File Link */
.file-link {{
    color: #74b9ff; text-decoration: none; font-size: 12px;
    display: inline-flex; align-items: center; gap: 3px; word-break: break-all;
}}
.file-link:hover {{ text-decoration: underline; color: #a8dcff; }}
.file-sep {{ color: #636e72; margin: 0 4px; }}

/* Amount */
.amount-cell {{ color: #fdcb6e; font-weight: 600; text-align: right; white-space: nowrap; }}

/* Footer */
.footer {{ text-align: center; padding: 24px; color: #636e72; font-size: 13px; }}
.footer a {{ color: #74b9ff; text-decoration: none; }}

/* Responsive */
@media (max-width: 768px) {{
    .summary-grid {{ grid-template-columns: repeat(2, 1fr); }}
    .kw-bar .kw-label {{ width: 70px; font-size: 11px; }}
    .kw-bar .kw-amount {{ width: 80px; font-size: 11px; }}
    table {{ font-size: 12px; }}
    thead th, tbody td {{ padding: 6px 8px; }}
}}
</style>
</head>
<body>
<div class="container">

<!-- Header -->
<div class="header">
    <h1>📊 2026年 杜书磊 负责市场区域预决算分析报告</h1>
    <div class="subtitle">预算文件关键字智能匹配 · 17关键字全覆盖 · 市州→区县→单位三级分层</div>
    <div class="date">数据范围：青海省（西宁市 · 海东市 · 省级） | 生成日期：2026年7月22日</div>
</div>

<!-- Summary Cards -->
<div class="summary-grid">
    <div class="sum-card c1">
        <div class="label">预算文件数</div>
        <div class="num">{total_files}<span class="unit">个</span></div>
    </div>
    <div class="sum-card c2">
        <div class="label">匹配项总数</div>
        <div class="num">{total_matches}<span class="unit">条</span></div>
    </div>
    <div class="sum-card c3">
        <div class="label">预算总金额</div>
        <div class="num">{total_amount:,.2f}<span class="unit">万元</span></div>
    </div>
    <div class="sum-card c4">
        <div class="label">覆盖市州</div>
        <div class="num">{len(cities)}<span class="unit">个</span></div>
    </div>
    <div class="sum-card c5">
        <div class="label">覆盖区县</div>
        <div class="num">{total_districts}<span class="unit">个</span></div>
    </div>
    <div class="sum-card c6">
        <div class="label">命中关键字</div>
        <div class="num">{kws_used}<span class="unit">/17</span></div>
    </div>
</div>

<!-- Keyword Distribution Chart -->
<div class="chart-section">
    <h2>📈 关键字分布统计</h2>
''')
    
    max_count = max(v["count"] for _, v in kw_stats_sorted) if kw_stats_sorted else 1
    for kw, stats in kw_stats_sorted:
        color = KW_COLORS.get(kw, "#636e72")
        icon = KW_ICONS.get(kw, "📌")
        pct = (stats["count"] / max_count * 100) if max_count > 0 else 0
        html_parts.append(f'''        <div class="kw-bar">
            <div class="kw-label">{icon} {kw}</div>
            <div class="kw-bar-bg">
                <div class="kw-bar-fill" style="width:{pct:.1f}%; background:{color};">{stats["count"]}次</div>
            </div>
            <div class="kw-amount">{stats["amount"]:,.2f}万元</div>
        </div>
''')
    
    html_parts.append('''</div>

<!-- Search -->
<input type="text" class="search-box" id="searchInput" placeholder="🔍 搜索区县、关键字、内容... (实时筛选)" onkeyup="filterContent()">

<!-- City Navigation -->
<div class="city-nav">
''')
    
    for city in cities:
        color = city_colors.get(city, "#636e72")
        city_amount = sum(m["amount"] for d in hierarchy[city].values() for ot in d.values() for m in ot)
        city_count = sum(len(ot) for d in hierarchy[city].values() for ot in d.values())
        html_parts.append(f'    <a href="#city-{city}" style="background:{color}22; color:{color}; border:1px solid {color}44;" onclick="toggleCity(\'city-{city}\')">{city} · {city_count}条 · {city_amount:,.2f}万元</a>\n')
    
    html_parts.append('</div>\n\n')

    # ===== City Sections =====
    for city in cities:
        color = city_colors.get(city, "#636e72")
        city_amount = sum(m["amount"] for d in hierarchy[city].values() for ot in d.values() for m in ot)
        city_count = sum(len(ot) for d in hierarchy[city].values() for ot in d.values())
        
        html_parts.append(f'''<!-- {city} Section -->
<div class="city-section open" id="city-{city}" data-search="{city}">
    <div class="city-header" style="border-left:4px solid {color};" onclick="toggleCity('city-{city}')">
        <h3 style="color:{color};">📍 {city}</h3>
        <div style="display:flex;align-items:center;gap:16px;">
            <span class="city-amount" style="color:#fdcb6e;">{city_amount:,.2f}万元</span>
            <span style="color:#636e72;font-size:13px;">{city_count}条匹配</span>
            <span class="toggle">▼</span>
        </div>
    </div>
    <div class="city-body">
''')
        
        for district in sorted(hierarchy[city].keys()):
            html_parts.append(f'        <div class="district-block" data-search="{district}">\n')
            html_parts.append(f'            <div class="district-title">📍 {district}</div>\n')
            
            for org_type in sorted(hierarchy[city][district].keys()):
                matches = hierarchy[city][district][org_type]
                merged = merge_matches(matches)
                org_total = sum(m["amount"] for m in merged)
                org_icon = org_icons.get(org_type, "📄")
                
                html_parts.append(f'''            <div class="org-block" data-search="{org_type}">
                <div class="org-header">
                    <span class="org-name">{org_icon} {org_type}</span>
                    <span class="org-sum">汇总：{org_total:,.2f}万元</span>
                </div>
                <table>
                    <thead>
                        <tr>
                            <th style="width:120px;">关键字</th>
                            <th>匹配内容</th>
                            <th style="width:100px;">位置</th>
                            <th style="width:110px;text-align:right;">预算金额</th>
                            <th style="width:180px;">来源文件</th>
                        </tr>
                    </thead>
                    <tbody>
''')
                
                for m in merged:
                    kw = m["keyword"]
                    color = KW_COLORS.get(kw, "#636e72")
                    icon = KW_ICONS.get(kw, "📌")
                    count_badge = f'<span class="kw-count">×{m["count"]}</span>' if m["count"] > 1 else ""
                    
                    # 合并内容（取前3条，每条截断）
                    contents = m["contents"][:3]
                    content_str = "; ".join(c[:80] for c in contents)
                    if m["count"] > 3:
                        content_str += f" ...等{m['count']}条"
                    
                    locations = ", ".join(m["locations"][:5])
                    if len(m["locations"]) > 5:
                        locations += f" ...等{len(m['locations'])}处"
                    
                    # 来源文件链接
                    source_files = list(set(mm.get("source_file", "") for mm in matches if mm["keyword"] == kw))
                    file_links = []
                    for sf in source_files:
                        href = f"{SUBDIR}/{sf}"
                        file_links.append(f'<a class="file-link" href="{href}" target="_blank">📄 {sf}</a>')
                    file_links_html = '<span class="file-sep">|</span>'.join(file_links)
                    
                    amount = m["amount"]
                    amount_str = f'{amount:,.2f}' if amount > 0 else '0.00'
                    amount_color = "#fdcb6e" if amount > 0 else "#636e72"
                    
                    html_parts.append(f'''                        <tr data-search="{kw} {content_str}">
                            <td><span class="kw-tag" style="background:{color}22; color:{color}; border:1px solid {color}44;">{icon} {kw}{count_badge}</span></td>
                            <td>{content_str}</td>
                            <td style="color:#636e72;font-size:12px;font-family:monospace;">{locations}</td>
                            <td class="amount-cell" style="color:{amount_color};">{amount_str}万元</td>
                            <td>{file_links_html}</td>
                        </tr>
''')
                
                html_parts.append('''                    </tbody>
                </table>
            </div>
''')
        
        html_parts.append('        </div>\n')
    
    html_parts.append('''    </div>
</div>

''')
    
    # ===== Footer =====
    html_parts.append(f'''
<!-- Footer -->
<div class="footer">
    <p>📊 2026年 杜书磊 负责市场区域预决算分析报告</p>
    <p>数据来源：{total_files}个PDF预算文件 | 17关键字全覆盖匹配 | 生成时间：2026年7月22日</p>
    <p>
        <a href="http://192.168.99.133:5678/2026-yjs-dsl-2026-report.html" target="_blank">内网访问</a> | 
        <a href="https://ziyuan.cdlhyj.com/2026-yjs-dsl-2026-report.html" target="_blank">外网访问</a>
    </p>
</div>

</div>

<script>
function toggleCity(id) {{
    var el = document.getElementById(id);
    el.classList.toggle('open');
}}

function filterContent() {{
    var query = document.getElementById('searchInput').value.toLowerCase().trim();
    var sections = document.querySelectorAll('.city-section');
    var districts = document.querySelectorAll('.district-block');
    var orgs = document.querySelectorAll('.org-block');
    var rows = document.querySelectorAll('tbody tr');
    
    if (!query) {{
        sections.forEach(s => s.classList.add('open'));
        districts.forEach(d => d.style.display = '');
        orgs.forEach(o => o.style.display = '');
        rows.forEach(r => r.style.display = '');
        return;
    }}
    
    sections.forEach(s => s.classList.add('open'));
    
    var hasMatch = false;
    rows.forEach(r => {{
        var text = (r.getAttribute('data-search') || '') + ' ' + r.textContent.toLowerCase();
        var match = text.includes(query);
        r.style.display = match ? '' : 'none';
        if (match) hasMatch = true;
    }});
    
    // Hide empty org blocks
    orgs.forEach(o => {{
        var visibleRows = o.querySelectorAll('tbody tr[style=""], tbody tr:not([style])');
        var hasVisible = false;
        o.querySelectorAll('tbody tr').forEach(r => {{
            if (r.style.display !== 'none') hasVisible = true;
        }});
        o.style.display = hasVisible ? '' : 'none';
    }});
    
    // Hide empty districts
    districts.forEach(d => {{
        var hasVisible = false;
        d.querySelectorAll('.org-block').forEach(o => {{
            if (o.style.display !== 'none') hasVisible = true;
        }});
        d.style.display = hasVisible ? '' : 'none';
    }});
    
    // Hide empty city sections
    sections.forEach(s => {{
        var hasVisible = false;
        s.querySelectorAll('.district-block').forEach(d => {{
            if (d.style.display !== 'none') hasVisible = true;
        }});
        s.style.display = hasVisible ? '' : 'none';
    }});
}}
</script>
</body>
</html>''')
    
    return '\n'.join(html_parts)

def main():
    data = load_data()
    html = build_html(data)
    
    with open(HTML_OUTPUT, 'w', encoding='utf-8') as f:
        f.write(html)
    
    print(f"HTML report generated: {HTML_OUTPUT}")
    print(f"File size: {os.path.getsize(HTML_OUTPUT) / 1024:.1f} KB")
    
    # 验证链接
    print("\n=== Link Verification ===")
    all_links = []
    for fname in data.keys():
        href = f"{SUBDIR}/{fname}"
        all_links.append((href, os.path.join(BASE_DIR, fname)))
    
    all_ok = True
    for href, fpath in all_links:
        exists = os.path.exists(fpath)
        status = "✅" if exists else "❌"
        if not exists:
            all_ok = False
        print(f"  {status} {href} → {fpath}")
    
    if all_ok:
        print(f"\n✅ All {len(all_links)} file links verified!")
    else:
        print(f"\n❌ Some links are broken!")
    
    print(f"\n📊 Report Summary:")
    total_matches = sum(len(info["matches"]) for info in data.values())
    total_amount = sum(m["amount"] for info in data.values() for m in info["matches"])
    print(f"  Files: {len(data)}")
    print(f"  Matches: {total_matches}")
    print(f"  Total amount: {total_amount:,.2f}万元")
    print(f"\n🔗 Internal: http://192.168.99.133:5678/2026-yjs-dsl-2026-report.html")
    print(f"🔗 External: https://ziyuan.cdlhyj.com/2026-yjs-dsl-2026-report.html")

if __name__ == "__main__":
    main()
