"""Write the same top navigation into every demo page, marking the current one: a bar with
home, the current category and its demos, and a 全部示例 panel listing every demo.

Run from the repo root:  python3 scripts/gen_nav.py
CATEGORIES is the single list of demos by category; www/index.html groups its cards the same way.
Add a new demo to its category here, then add its card to the matching <section> on the home page.
"""
import html
import pathlib
import re
import sys

ROOT = pathlib.Path(__file__).resolve().parent.parent

# (key, label, one-line description, [(slug, short name), ...]) — order = home page + nav order
CATEGORIES = [
    ('graphics', '🎨 图形渲染', '分形、光栅化、光线追踪与程序化生成', [
        ('mandelbrot', '曼德博集合'), ('mandelbulb', '曼德博球'), ('terrain', '噪声地形'),
        ('rasterizer', '软件光栅化'),
        ('pathtracer', '光线追踪'),
        ('wfc', '波函数坍缩'),
    ]),
    ('simulation', '⚛️ 物理模拟', '粒子、流体、布料与元胞自动机', [
        ('particles', '粒子物理'), ('webgpu', 'WebGPU'), ('fluid', '流体模拟'), ('game-of-life', '生命游戏'),
        ('cloth', '布料模拟'),
    ]),
    ('algorithms', '🧮 算法与性能', '数据处理、搜索、几何与性能对比', [
        ('data-table', '数据表格'), ('pathfind', '迷宫寻路'), ('benchmark', '性能对比'),
        ('simd', 'SIMD 加速'),
        ('delaunay', '三角剖分'),
        ('sudoku', '数独求解'),
        ('server-compute', '浏览器 vs 服务端'),
    ]),
    ('media', '🎬 多媒体', '图像、视频与音频处理', [
        ('image-filter', '图像滤镜'), ('video-filter', '视频滤镜'), ('spectrum', '音频频谱'),
        ('synth', '合成器'),
        ('seam-carving', '智能缩放'),
        ('jpeg', 'JPEG'),
    ]),
    ('tools', '🛠️ 实用工具', '在浏览器本地完成的实用计算', [
        ('sha256', '文件哈希'),
        ('qrcode', '二维码'),
        ('compress', '数据压缩'),
        ('markdown', 'Markdown'),
        ('mcp', 'MCP 调试台'),
    ]),
    ('games', '🎮 游戏与 AI', '可以上手玩的互动演示', [
        ('falling-sand', '落沙游戏'),
        ('gomoku', '五子棋 AI'),
        ('digits', '手写识别'),
        ('chip8', 'CHIP-8'),
    ]),
]
DEMOS = [d for _, _, _, demos in CATEGORIES for d in demos]

NAV_RE = re.compile(r'    <nav class="top-nav"[^>]*>.*?</nav>\n', re.S)
BODY_RE = re.compile(r'<body(?: class="([^"]*)")?>')
SCRIPT = '    <script src="../nav.js" defer></script>\n'


def link(slug, name, current, indent):
    mark = ' aria-current="page"' if slug == current else ''
    return f'{indent}<a href="../{slug}/"{mark}>{html.escape(name)}</a>'


def render(current):
    """The bar shows home, the current category and its demos; 全部示例 opens a panel with
    every demo by category (a <details>, so it works without script)."""
    category = next(c for c in CATEGORIES if any(slug == current for slug, _ in c[3]))
    name = dict(DEMOS)[current]
    lines = ['    <nav class="top-nav" aria-label="示例导航">',
             '        <a class="nav-home" href="../">← 首页</a>',
             f'        <span class="nav-cat">{html.escape(category[1].split(" ", 1)[1])}</span>',
             f'        <span class="nav-here">{html.escape(name)}</span>',
             '        <div class="nav-siblings">']
    lines += [link(slug, n, current, ' ' * 12) for slug, n in category[3]]
    lines += ['        </div>',
              '        <details class="nav-all">',
              '            <summary>全部示例</summary>',
              '            <div class="nav-panel">']
    for _, label, _, demos in CATEGORIES:
        lines.append('                <div class="nav-group">')
        lines.append(f'                    <span class="nav-group-title">{html.escape(label)}</span>')
        lines += [link(slug, n, current, ' ' * 20) for slug, n in demos]
        lines.append('                </div>')
    lines += ['            </div>', '        </details>', '    </nav>']
    return '\n'.join(lines) + '\n'


def with_nav_class(page):
    """Give <body> the has-nav class, which reserves room for the fixed bar."""
    def add(m):
        classes = (m.group(1) or '').split()
        return m.group(0) if 'has-nav' in classes else f'<body class="{" ".join(classes + ["has-nav"])}">'
    return BODY_RE.sub(add, page, count=1)


def main():
    for slug, _ in DEMOS:
        page = ROOT / 'www' / slug / 'index.html'
        text = page.read_text(encoding='utf-8')
        if len(NAV_RE.findall(text)) != 1:
            sys.exit(f'{page}: expected exactly one <nav class="top-nav">')
        text = with_nav_class(NAV_RE.sub(lambda _: render(slug), text))
        if SCRIPT not in text:
            text = text.replace('</head>', SCRIPT + '</head>', 1)
        page.write_text(text, encoding='utf-8')
        print(f'nav → {slug}')


if __name__ == '__main__':
    main()
