# Render labeled exterior views and geometry-only slices with the optional proc tools.
import argparse
import json
from pathlib import Path
import subprocess
import sys
from hearth.persistence import export_scene, load_scene, companion_path
from hearth.programs import settlement_scene

RENDER = Path('/opt/tools/render_schematic.mjs')
CUTAWAY = Path('/opt/tools/cutaway.py')
VITE = Path('/work/generator/MCRender/node_modules/.bin/vite-node')


def render(source, target, azimuth, elevation, size, radius):
    subprocess.run(['xvfb-run', '-a', str(VITE), '--script', str(RENDER), '--', '--input', str(source), '--output', str(target), '--size', str(size), '--azimuth', str(azimuth), '--elevation', str(elevation), '--radius', str(radius), '--fov', '30', '--ambient', '0.8'], check=True)


def preview(seed, source, output, size=1200, cutaways=False):
    output.mkdir(parents=True, exist_ok=True)
    if source is None:
        source = output / 'source.litematic'
        export_scene(settlement_scene(seed), source)
    scene = load_scene(source)
    if scene.seed != seed:
        raise ValueError(f'--seed {seed} does not match the input artifact seed {scene.seed}')
    views = [('front', 210, 28, 3.5), ('rear', 30, 26, 3.5)]
    records = []
    for label, azimuth, elevation, radius in views:
        target = output / (label + '.png')
        render(source, target, azimuth, elevation, size, radius)
        records.append({'source': str(source), 'seed': seed, 'label': label, 'image': str(target), 'azimuth': azimuth, 'elevation': elevation})
    if cutaways:
        building = next(n for n in scene.nodes.values() if n.type == 'building.rooms')
        floor = building.contract.decisions['floor'] + building.frame.origin[1]
        offset = json.loads(companion_path(source).read_text())['offset']
        cuts = [('floor-cut', 'y', floor + 4 - offset[1], 210, 64)]
        stair = next((n for n in scene.nodes.values() if n.type == 'circulation.stair'), None)
        if stair is not None:
            occupied = scene.cells(stair.path)
            # Cut beside the actual flight, including flights in a remote wing.
            axis = min((0, 2), key=lambda i: max(p[i] for p in occupied) - min(p[i] for p in occupied))
            limit = max(p[axis] for p in occupied) + 1 - offset[axis]
            cuts.append(('stair-cut', 'xz'[axis // 2], limit, 110 if axis == 0 else 20, 26))
        for label, axis, limit, azimuth, elevation in cuts:
            cut = output / (label + '.litematic')
            subprocess.run([sys.executable, str(CUTAWAY), '--input', str(source), '--output', str(cut), '--axis', axis, '--max', str(limit), '--name', label], check=True)
            target = output / (label + '.png')
            render(cut, target, azimuth, elevation, size, 3.2)
            records.append({'source': str(source), 'seed': seed, 'label': label, 'axis': axis, 'export_local_cut': limit, 'image': str(target), 'geometry_preview_only': True})
    (output / 'views.json').write_text(json.dumps(records, indent=2))


if __name__ == '__main__':
    p = argparse.ArgumentParser()
    p.add_argument('--seed', type=int, default=0)
    p.add_argument('--input', type=Path)
    p.add_argument('--output', type=Path, default=Path('previews/default'))
    p.add_argument('--size', type=int, default=1200)
    p.add_argument('--cutaways', action='store_true')
    a = p.parse_args()
    preview(a.seed, a.input, a.output, a.size, a.cutaways)
