# Replay the frozen extension manifest and compare complete structural records and actual NBT.
import argparse
import json
from pathlib import Path
import subprocess
import sys
import tempfile
from hearth import Scene
from hearth.environment import Terrain
from hearth.environment.fields import from_expression
from hearth.persistence import load_scene, semantic_digest, encode
from hearth_extensions.assessment import PROBE_DOMAIN, freeze_probe, connector_scene, boundary_scene, hall_scene
from hearth_extensions.programs import extension_scene, branching_campus, perimeter_cluster


def replay(row):
    """Reconstruct one explicit assessment recipe from its recorded inputs.

    Args:
        row (dict): A selected row in the extension replay manifest.

    Returns:
        Scene: A validated, freshly generated scene without filesystem output.
    """
    inputs = row['inputs']
    seed = inputs['structure_seed']
    group = row['label'].split('-')[0]
    if group == 'connector':
        environment = freeze_probe(inputs['environment']['environment_seed'])
        if semantic_digest(environment) != inputs['environment']['digest']:
            raise AssertionError('Frozen terrain changed')
        return connector_scene(environment, seed)
    if group == 'boundary':
        environment = Scene(inputs['environment_seed'], domain=PROBE_DOMAIN)
        environment.place('land', Terrain(PROBE_DOMAIN, from_expression(inputs['expression'])))
        environment.finalize()
        return boundary_scene(environment, seed)
    if group == 'hall':
        return hall_scene(seed, inputs['environment_seed'])
    programs = {'campus': branching_campus, 'perimeter': perimeter_cluster}
    return extension_scene(programs[inputs['program']], seed, inputs['environment_seed'])


def audit(seed: int, manifest: Path, output: Path, cli: bool = False):
    """Check replay identity, structural graphs, queries, inventories and optional original CLI.

    Args:
        seed (int): Root assessment seed, used to verify the selected manifest.
        manifest (Path): Explicit batch artifact manifest.
        output (Path): Audit report destination.
        cli (bool): Also exercise the unchanged no-argument and seed-1 CLI in a temporary directory.

    Returns:
        dict: Completed audit with every selected input and result.
    """
    entries = json.loads(manifest.read_text())
    if entries[0]['inputs']['environment']['environment_seed'] != seed * 100:
        raise ValueError('Root seed does not match the selected assessment manifest')
    rows = []
    for row in entries:
        native = replay(row)
        restored = load_scene(Path(row['artifact']))
        assert semantic_digest(native) == row['digest'] == semantic_digest(restored), row['label']
        for field in ('nodes', 'relations', 'dependencies', 'operations', 'port_uses', 'displaced'):
            assert encode(getattr(native, field)) == encode(getattr(restored, field)), (row['label'], field)
        assert native.reverse == restored.reverse, row['label']
        assert {p: c.nbt for p, c in native.blocks.items()} == {p: c.nbt for p, c in restored.blocks.items()}
        points = [min(native.cells(n)) for n in sorted(native.nodes) if native.cells(n)]
        for point in points:
            assert native.inspect(point) == restored.inspect(point), (row['label'], point)
        rows.append({'label': row['label'], 'digest': row['digest'], 'nodes': len(native.nodes), 'blocks': len(native.blocks), 'component_queries': len(points), 'inventories': sum(c.nbt is not None for c in native.blocks.values()), 'verified': True})
    cli_rows = []
    if cli:
        root = Path(__file__).resolve().parents[1]
        with tempfile.TemporaryDirectory(dir=root / 'test', prefix='tmp-extension-cli-') as directory:
            temporary = Path(directory)
            for name, arguments, filename in (('default', [], 'output.litematic'), ('seed-1', ['--seed', '1', '--output', str(temporary / 'explicit path with spaces.litematic')], 'explicit path with spaces.litematic')):
                subprocess.run([sys.executable, str(root / 'generate.py'), *arguments], cwd=temporary, check=True)
                scene = load_scene(temporary / filename)
                cli_rows.append({'command': name, 'seed': scene.seed, 'blocks': len(scene.blocks), 'nodes': len(scene.nodes), 'digest': semantic_digest(scene), 'verified': True})
    result = {'root_seed': seed, 'manifest': str(manifest), 'verified': True, 'artifacts': rows, 'original_cli': cli_rows}
    output.parent.mkdir(parents=True, exist_ok=True)
    output.write_text(json.dumps(result, indent=2))
    return result


if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('--seed', type=int, default=0)
    parser.add_argument('--manifest', type=Path, default=Path('samples/extensions/replay-manifest.json'))
    parser.add_argument('--output', type=Path, default=Path('reports/extension-corpus/artifact-audit.json'))
    parser.add_argument('--cli', action='store_true')
    args = parser.parse_args()
    audit(args.seed, args.manifest, args.output, args.cli)
