#!/usr/bin/env python3
"""Writes ix_status.js for the index page (36_index.html): which page-58 kill pages and kit demos exist, and how many
kills each weapon page has playable. The coordinator runs it at every check-in and before every pages commit.

  python3 _tools/ix_status.py            (from the feedback folder or anywhere)

A weapon page counts as LIVE only when its 58k_<id>.html loads the shared shell (58k_page.js); a page without the shell is
a builder's test harness and shows as BUILDING. Live pages are opened in headless Chrome (private profile, --headless=new)
and the counts are read from the page itself, so the index shows what the user will actually see."""
import json, os, subprocess, time

ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

# (id, aliases) per weapon; the page may use the K40 id or the builder's short name
WEAPONS = [
    ('pistol', []), ('revolver', []), ('handcannon', ['hcannon']), ('smg', []), ('golden', []),
    ('ar', []), ('burst', []), ('sniper', []), ('bouncer', []),
    ('pump', []), ('sawedoff', []), ('minigun', []), ('flamer', []),
    ('rpg', []), ('gl', []), ('cluster', []), ('fists', []),
    ('laser', []), ('beam', []), ('shrink', []), ('gravflip', []), ('ice', []), ('glue', []), ('portalgun', ['portal']),
    ('speedsabre', ['sabre']), ('knife', []), ('hammer', []), ('spear', []), ('pan', []),
    ('thammer', ['thunder']), ('scythe', []), ('tkglove', ['tk']), ('tpdagger', []),
]
KITS = ['body', 'world', 'replay', 'sound']


def exists(name):
    return os.path.isfile(os.path.join(ROOT, name))


def read(name):
    try:
        with open(os.path.join(ROOT, name), encoding='utf-8', errors='replace') as f:
            return f.read()
    except OSError:
        return ''


def counts(page, wid):
    """Open a live page headless (via ix_probe.mjs) and read its own kill registry."""
    try:
        # nice 20 like the page agents' render slots, so the index refresh never competes with their renders
        r = subprocess.run(['nice', '-n', '20', 'node', os.path.join(ROOT, '_tools', 'ix_probe.mjs'), page, wid], capture_output=True, text=True,
                           timeout=120, cwd=ROOT)
        d = json.loads(r.stdout.strip().splitlines()[-1])
    except (subprocess.TimeoutExpired, OSError, ValueError, IndexError):
        return None
    reg = d.get('reg') or {}
    return {'new': reg.get('newReady'), 'newOf': reg.get('new'), 'skins': reg.get('skinsReady'), 'skinsOf': reg.get('skins'), 'mids': reg.get('midsReady'), 'midsOf': reg.get('mids'),
            'errors': len(d.get('errors') or [])}


def main():
    out = {'updated': time.strftime('%d %b %H:%M'), 'weapons': {}, 'kits': {}, 'hub': exists('58_kill_library.html'),
           'p56': exists('56_decisions.html'), 'board': exists('51_build.html')}
    for wid, aliases in WEAPONS:
        names = [wid] + aliases
        page = next((f'58k_{n}.html' for n in names if exists(f'58k_{n}.html')), None)
        lane = any(f.startswith('58k_w_') and f.endswith('.js') and any(f[6:].startswith(n) for n in names)
                   for f in os.listdir(ROOT))
        live = bool(page) and '58k_page.js' in read(page)
        w = {'page': page if live else None, 'started': lane or bool(page)}
        if live:
            c = counts(page, wid)
            if c:
                w.update(c)
        out['weapons'][wid] = w
    for k in KITS:
        out['kits'][k] = {'page': f'58k_kit_{k}.html' if exists(f'58k_kit_{k}.html') else None}
    js = '/* generated by _tools/ix_status.py for 36_index.html; do not edit */\nwindow.IX = ' + json.dumps(out, indent=1) + ';\n'
    with open(os.path.join(ROOT, 'ix_status.js'), 'w', encoding='utf-8') as f:
        f.write(js)
    live = [k for k, v in out['weapons'].items() if v.get('page')]
    print('ix_status.js: live', live, '· started', [k for k, v in out['weapons'].items() if v['started'] and not v.get('page')])


if __name__ == '__main__':
    main()
