# Frozen ridge-lightwell corpus with measured actual composition and retained outcomes.
import argparse
import json
from pathlib import Path
from hearth import Scene, Box
from hearth.environment import Terrain, gradient, wave, radial
from hearth.components import adapted
from hearth.randomness import Scope
from hearth.persistence import encode, semantic_digest
from hearth.quality_assessment import evaluate, summary
from hearth.lodges import lodge_scene
from examples.lantern_house import lantern_house


def measurements(scene):
    lanterns = [n for n in scene.nodes.values() if n.type == 'roof.ridge-lantern']
    roofs = [n for n in scene.nodes.values() if n.type == 'roof.weather-cover']
    return {'lanterns': len(lanterns), 'lengths': [n.contract.decisions['length'] for n in lanterns], 'current_cells': sum(len(scene.cells(n.path, True)) for n in lanterns), 'mounts': [{'component': n.path, 'selected': n.contract.decisions['ridge_mount'], 'screened_out': n.contract.decisions['ridge_candidates'], 'optional_omission': n.contract.decisions['omitted_optional_ridge']} for n in roofs]}


def run(seed, output, artifacts):
    output.mkdir(parents=True, exist_ok=True)
    artifacts.mkdir(parents=True, exist_ok=True)
    domain = Box((-10, -4, -20), (58, 80, 58))
    environments, inputs, rows = [], [], []
    for index in range(16):
        es = 7100 + seed * 100 + index
        rng = Scope(es).stream('lantern-environment')
        field = gradient(rng.choice((-.025, 0, .025)), rng.choice((-.02, 0, .02)), 4) + wave(rng.choice((0, .35)), .11, .08, rng.random() * 6)
        field = field.blend(gradient(.01, -.01, 4) + radial(20, 16, 35, .6), radial(9, 13, 42, .7))
        if index >= 8:
            field = field.transformed(dx=3, dz=-2, scale=1.2) + wave(.2, .07, .13, rng.random() * 6) * radial(18, 10, 50, 1)
        field = field.clamp(2, 6)
        water = rng.choice((None, 4, 5))
        scene = Scene(es, domain=domain)
        scene.place('land', Terrain(domain, field, water))
        scene.finalize()
        environments.append(scene)
        inputs.append({'environment_seed': es, 'expression': field.expression(), 'water': water, 'digest': semantic_digest(scene), 'held_out_composition': index >= 8})
    (output / 'frozen-inputs.json').write_text(json.dumps(inputs, indent=2))

    def retain(label, specification, recipe, artifact):
        observed = {}

        def measure():
            scene = recipe()
            observed.update(measurements(scene))
            if not observed['lanterns']:
                raise AssertionError('This supported client must realize at least one glazed lightwell')
            return scene

        row = evaluate(label, specification, measure, artifact)
        row['ridge_lights'] = observed
        rows.append(row)
        (output / 'results.json').write_text(json.dumps(rows, indent=2))
        print(label, row['status'], flush=True)

    for bs in range(8):
        artifact = artifacts / f'lantern-house-{bs}.litematic' if bs in (0, 1, 4, 7) else None
        retain(f'lantern-house-{bs}', {'structure_seed': bs, 'environment_seed': seed * 100 + bs, 'design': encode(lantern_house(bs))}, lambda b=bs: lodge_scene(lantern_house(b), b, seed * 100 + b), artifact)
    for index, environment in enumerate(environments):
        for bs in (1, 6):

            def place(e=environment, b=bs):
                scene = e.fork(seed=b)
                scene.compose_choice(adapted('building', lantern_house(b), '/land'))
                return scene.finalize()

            label = f'pair-{index}-{bs}'
            artifact = artifacts / (label + '.litematic') if (index, bs) in ((0, 1), (3, 6), (10, 1), (15, 6)) else None
            retain(label, {**inputs[index], 'structure_seed': bs, 'design': encode(lantern_house(bs))}, place, artifact)
            if semantic_digest(environment) != inputs[index]['digest']:
                raise AssertionError('Frozen environment changed')
    result = {'client': summary(rows[:8]), 'independent_pairs': summary(rows[8:])}
    (output / 'summary.json').write_text(json.dumps(result, indent=2))
    (artifacts / 'manifest.json').write_text(json.dumps([r for r in rows if 'artifact' in r], indent=2))
    return result


if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('--seed', type=int, default=0)
    parser.add_argument('--output', type=Path, default=Path('reports/building-lantern/new'))
    parser.add_argument('--artifacts', type=Path, default=Path('samples/building-lantern/new'))
    args = parser.parse_args()
    print(json.dumps(run(args.seed, args.output, args.artifacts), indent=2))
