param(
    [Parameter(Mandatory=$true)][string]$Root,
    [Parameter(Mandatory=$true)][string]$Output
)
$ErrorActionPreference='Stop'
. (Join-Path $PSScriptRoot 'CPUReportIO.ps1')
if(-not[IO.Path]::IsPathRooted($Output) -or (Test-Path -LiteralPath $Output)){throw 'Use a new absolute report directory'}
New-Item -ItemType Directory -Path $Output | Out-Null
$source=Join-Path $Root 'results.json';$run=Get-Content -LiteralPath $source -Raw | ConvertFrom-Json
if(-not$run.completed_requested_run -or $run.case_count -le 0 -or $run.cases.Count -ne $run.case_count -or
    $run.mode -notin @('audio','timing') -or $run.results.Count -ne $run.case_count*$run.repeat_count){throw 'Cannot export an incomplete measurement run'}
function Save($Value,[string]$Name){$Value | ConvertTo-Json -Depth 40 | Set-Content -LiteralPath (Join-Path $Output $Name) -Encoding utf8}
New-Item -ItemType HardLink -Path (Join-Path $Output 'results.json') -Target ([IO.Path]::GetFullPath($source)) | Out-Null
Save @{configuration=$run.configuration;targetVersion=$run.target_version;executableSha256=$run.executable_sha256;
    syntheticUnitFixture=[bool]$run.syntheticUnitFixture;
    provenance=$run.provenance;metadataSha256=$run.metadata_sha256;startedUtc=$run.started_utc;completedUtc=$run.completed_utc;
    originalRun=[IO.Path]::GetFullPath($Root);fullMilestonePass=$false} 'environment.json'
Save @{manifestVersion=$run.manifest_version;selectedManifestSha256=$run.selected_manifest_sha256;cases=$run.cases;
    prerollSeconds=.25;prerollRounding='ceil to nominal regular blocks';timingWarmup='one complete discarded fresh-instance render before measured repetitions';
    dataSource='actual executable manifest; no replacement fixtures';fullMilestonePass=$false} 'scenarios.json'
$cases=@{};$families=@{};$results=@{}
foreach($case in $run.cases){
    if($cases.ContainsKey($case.id)){throw 'Duplicate scenario'}
    $cases[$case.id]=$case
    if(-not$families.ContainsKey($case.family)){$families[$case.family]=0};$families[$case.family]++
}
$csv=[Collections.Generic.List[object]]::new()
foreach($row in $run.results){
    $key="$($row.id)/$($row.repeat)"
    if(-not$cases.ContainsKey($row.id) -or $results.ContainsKey($key) -or $row.repeat -lt 0 -or $row.repeat -ge $run.repeat_count){throw 'Invalid result coverage'}
    $results[$key]=$true;$case=$cases[$row.id]
    $phases=if($run.mode -eq 'timing'){@($row.total)+@($row.phases)}else{@([pscustomobject]@{valid=$false})}
    $first=$true
    foreach($phase in $phases){
        $name=if($first){'whole-clip'}else{$phase.name}
        $record=[ordered]@{case_id=$row.id;family=$case.family;repeat=$row.repeat;phase=$name;mode=$run.mode;
            configuration=$run.configuration;target_version=$run.target_version;executable_sha256=$run.executable_sha256;
            environment_sha256=$run.provenance.environment_sha256;source_sha256=$run.provenance.source_sha256;
            input_sha256=$row.manifest_sha256;sample_rate_hz=$case.sample_rate;nominal_block_samples=$case.nominal_block_size;
            clip_frames=$row.frames;phase_frames=$(if($first){$row.frames}else{$phase.blocks*$case.nominal_block_size});
            variable_rate_block_plan=[bool]$case.lifecycle_plan;polyphony_requested=$case.polyphony_requested;
            max_active_voices=$row.max_active_voices;unison=$case.raw_applied[29];oscillator2_enabled=$case.raw_applied[24];
            waveform1=$case.raw_applied[40];waveform2=$case.raw_applied[42];fx_order=$case.raw_applied[61];
            construct_seconds=$row.construct_seconds;prepare_seconds=$row.prepare_seconds;preroll_seconds=$row.preroll_seconds;
            cold_first_callback_seconds=$row.cold_first_callback_seconds;loop_wall_seconds=$row.loop_wall_seconds;
            timing_valid=$phase.valid;blocks=$phase.blocks;callback_seconds=$phase.callback_seconds;audio_seconds=$phase.audio_seconds;
            rtf=$phase.rtf;average_block_seconds=$phase.average_block_seconds;max_block_seconds=$phase.max_block_seconds;
            p50_seconds=$phase.p50_seconds;p95_seconds=$phase.p95_seconds;p99_seconds=$phase.p99_seconds;p999_seconds=$phase.p999_seconds;
            max_block_ratio=$phase.max_block_ratio;deadline_misses=$phase.deadline_misses;empty_callbacks=$row.empty_callbacks;
            mixed_boundary_blocks=$row.mixed_boundary_blocks;mixed_boundary_samples=$row.mixed_boundary_samples;
            audio_sha256=$row.audio_sha256;reference_audio_sha256=$row.reference_audio_sha256;
            samples_over_0dbfs=$row.samples_over_0dbfs;lifecycle_sha256=$row.lifecycle_sha256;
            oscillator_lfo_phase_sha256=$row.oscillator_and_lfo_phase_sha256;first_no_voices_after_off_sample=$row.first_no_voices_after_off_sample;
            bit_identical_to_reference=$row.equivalence.bit_identical;
            numerical_comparison_json=($row.equivalence | ConvertTo-Json -Depth 8 -Compress);
            paired_source_directory=$row.paired_source_directory;requested_run_completed=$run.completed_requested_run;full_milestone_pass=$false}
        for($i=0;$i -lt 4;$i++){
            $channel=@('L','R','M','S')[$i]
            $record["peak_${channel}_fs"]=$(if($row.peak_L_R_M_S){$row.peak_L_R_M_S[$i]}else{$null})
            $record["rms_${channel}_fs"]=$(if($row.rms_L_R_M_S){$row.rms_L_R_M_S[$i]}else{$null})
        }
        $csv.Add([pscustomobject]$record);$first=$false
    }
}
foreach($case in $run.cases){for($r=0;$r -lt $run.repeat_count;$r++){if(-not$results.ContainsKey("$($case.id)/$r")){throw 'Missing case repetition'}}}
Export-CPUCsv $csv (Join-Path $Output 'results.csv')
Save @{caseCount=$run.case_count;repeatCount=$run.repeat_count;resultCount=$run.results.Count;csvPhaseRows=$csv.Count;
    expectedFullCaseCount=$(if($run.suite -eq 'representative'){39}else{7920});familyCounts=$families;caseIds=$run.cases.id;
    ratesHz=@($run.cases.sample_rate | Sort-Object -Unique);nominalBlockSamples=@($run.cases.nominal_block_size | Sort-Object -Unique);
    requestedPolyphony=@($run.cases.polyphony_requested | Sort-Object -Unique);
    mergedInputs=$run.mergedInputs;pairedSourceRoot=$run.paired_source_root;
    completeRequestedCoverage=$true;completeRequiredInventoryStillRequiresValidation=$true;fullMilestonePass=$false} 'coverage.json'
Write-Host "Exported $($run.case_count) cases, $($run.results.Count) repetitions, $($csv.Count) full phase/metric CSV rows. Not milestone approval."
