# Frozen finite assessment of new roof/interior compositions, with every outcome retained.
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, fingerprint
from hearth.lodges import lodge_scene
from examples.hearth_house import hearth_house


def furniture_measurements(scene):
    nodes = [n for n in scene.nodes.values() if 'furniture' in n.capability.tags]
    units = [n for n in nodes if 'interaction' in n.capability.offers]
    data = [(n.type, n.frame.turn, sorted(n.frame.inverse(p) for p in scene.cells(n.path))) for n in units]
    return {'stations': len(units), 'hearths': sum(n.type == 'furnishing.hearth' for n in nodes), 'dining_lengths': [n.contract.decisions['length'] for n in nodes if n.type == 'furnishing.dining-set'], 'interior_signature': fingerprint(data), 'optional_omissions': [{'component': n.path, 'omissions': n.contract.decisions['omitted_optional_stations']} for n in nodes if n.contract.decisions.get('omitted_optional_stations')]}


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, 72, 58))
    environments, inputs, rows = [], [], []
    for index in range(8):
        es = 6100 + seed * 100 + index
        rng = Scope(es).stream('craft-environment')
        field = (gradient(rng.choice((-.025, 0, .025)), rng.choice((-.02, .02)), 4) + wave(.35, .11, .08, rng.random() * 6)).blend(gradient(.02, -.01, 4) + radial(20, 18, 35, .6), radial(11, 12, 42, .7)).clamp(2, 6)
        water = rng.choice((None, 4, 5))
        s = Scene(es, domain=domain)
        s.place('land', Terrain(domain, field, water))
        s.finalize()
        environments.append(s)
        inputs.append({'environment_seed': es, 'expression': field.expression(), 'water': water, 'digest': semantic_digest(s)})
    (output / 'frozen-inputs.json').write_text(json.dumps(inputs, indent=2))

    def retain(label, inputs, recipe, artifact):
        measurements = {}

        def measured():
            scene = recipe()
            measurements.update(furniture_measurements(scene))
            return scene

        row = evaluate(label, inputs, measured, artifact)
        row['furnishings'] = measurements
        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'hearth-home-{bs}.litematic' if bs in (0, 2, 5, 7) else None
        retain(f'hearth-home-{bs}', {'structure_seed': bs, 'environment_seed': seed * 100 + bs, 'design': encode(hearth_house(bs))}, lambda b=bs: lodge_scene(hearth_house(b), b, seed * 100 + b), artifact)
    for index, environment in enumerate(environments):
        for bs in (1, 6):

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

            label = f'pair-{index}-{bs}'
            artifact = artifacts / (label + '.litematic') if (index, bs) in ((0, 1), (3, 6), (7, 1)) else None
            retain(label, {**inputs[index], 'structure_seed': bs, 'design': encode(hearth_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-craft/new'))
    parser.add_argument('--artifacts', type=Path, default=Path('samples/building-craft/new'))
    args = parser.parse_args()
    print(json.dumps(run(args.seed, args.output, args.artifacts), indent=2))
