#!/usr/bin/env python3
"""Headless screenshots of a house viewer, so changes can be checked by looking at them.

Usage:
  python tools/render_check.py houses/1351-leighton/index.html
  python tools/render_check.py houses/1351-leighton/index.html --views ne,n,sw,top
  python tools/render_check.py houses/1351-leighton/index.html --click upperDeck --views sw
  python tools/render_check.py houses/1351-leighton/index.html --cam="-7,16.5,42.5:0.3,16.2,39" --name bracket

  --views   named views from the viewer's dropdown (n s e w ne nw sw se top plan1 plan2)
  --click   ids of checkboxes to toggle before shooting (comma separated), e.g. upperDeck,site,lot
  --plan    2D plan mode shots for these floors (comma separated), e.g. 1,2 → plan2d_1.png, plan2d_2.png
  --cut     open the house at a floor (1, 2, …; needs a house with an interior); plan views do this themselves
  --cam     a custom camera "x,y,z:tx,ty,tz" in model feet; good for close-ups of details
  --out     output folder (default: renders/ next to the html)

Setup (once):  pip install playwright  &&  python -m playwright install chromium
WebGL runs on SwiftShader (software), so the first frame takes a few seconds.
"""
import argparse, asyncio, pathlib
from playwright.async_api import async_playwright

ARGS = ['--use-gl=angle', '--use-angle=swiftshader', '--enable-unsafe-swiftshader', '--ignore-gpu-blocklist']

async def main(a):
    html = pathlib.Path(a.html).resolve()
    out = pathlib.Path(a.out) if a.out else html.parent / 'renders'
    out.mkdir(parents=True, exist_ok=True)
    async with async_playwright() as p:
        b = await p.chromium.launch(args=ARGS)
        pg = await b.new_page(viewport={'width': a.width, 'height': a.height})
        errors = []
        pg.on('pageerror', lambda e: errors.append(str(e)))
        pg.on('console', lambda m: m.type == 'error' and errors.append(m.text))
        await pg.goto(html.as_uri()+(('#'+a.hash) if a.hash else ''))   # --hash deckPitch=7: reload-type options
        await pg.wait_for_function('window.__viewer', timeout=30000)
        await pg.wait_for_timeout(5000)
        for kv in filter(None, (a.opt or '').split(',')):          # --opt trimColor=black,deckGable=rafter
            k,v=kv.split('='); await pg.evaluate(f"HV.setOption('{k}','{v}')"); await pg.wait_for_timeout(200)
        for cid in filter(None, (a.click or '').split(',')):
            await pg.evaluate(f"document.getElementById('{cid}').click()")
            await pg.wait_for_timeout(400)
        if a.cut is not None:
            await pg.evaluate(f"window.__viewer.setCut({a.cut})")
            await pg.wait_for_timeout(400)
        shots = []
        if a.cam:
            pos, tgt = (list(map(float, part.split(','))) for part in a.cam.split(':'))
            await pg.evaluate(f"window.__viewer.setCamera({pos},{tgt})")
            await pg.wait_for_timeout(1200)
            f = out / f'{a.name or "custom"}.png'; await pg.screenshot(path=str(f), timeout=120000); shots.append(f)
        for n in filter(None, (a.plan or '').split(',')):
            await pg.evaluate(f"window.__viewer.setMode('plan'); window.__viewer.planLevel({n})")
            await pg.wait_for_timeout(600)
            f = out / f'plan2d_{n}.png'; await pg.screenshot(path=str(f), timeout=120000); shots.append(f)
        if a.plan: await pg.evaluate("window.__viewer.setMode('3d')"); await pg.wait_for_timeout(400)
        for v in filter(None, (a.views or ('' if (a.cam or a.plan) else 'ne')).split(',')):
            await pg.evaluate(f"window.__viewer.goView('{v}')")
            await pg.wait_for_timeout(1500)
            f = out / f'{v}.png'; await pg.screenshot(path=str(f), timeout=120000); shots.append(f)
        await b.close()
    for f in shots: print(f)
    if errors:
        print('\nPAGE ERRORS:'); [print(' ', e) for e in errors]

if __name__ == '__main__':
    ap = argparse.ArgumentParser()
    ap.add_argument('html'); ap.add_argument('--views'); ap.add_argument('--click'); ap.add_argument('--opt'); ap.add_argument('--hash')
    ap.add_argument('--cam'); ap.add_argument('--cut', type=int); ap.add_argument('--plan'); ap.add_argument('--name'); ap.add_argument('--out')
    ap.add_argument('--width', type=int, default=1400); ap.add_argument('--height', type=int, default=860)
    asyncio.run(main(ap.parse_args()))
