<?php

declare(strict_types=1);

$names = [
    'B_code' => 'B-code-receipt.json',
    'C_code' => 'C-code-receipt.json',
    'B_scan' => 'B-scan-receipt.json',
    'C_failed_scan' => 'C-scan-failed-receipt.json',
    'C_retry_scan' => 'C-scan-retry-receipt.json',
    'C_exact_expiry' => 'C-expire-owned-receipt.json',
    'B_fixture10001' => 'B-fixture10001-receipt.json',
    'C_fixture10001' => 'C-fixture10001-receipt.json',
    'B_recharge10001' => 'B-fixture10001-recharge-receipt.json',
    'C_recharge10001' => 'C-fixture10001-recharge-receipt.json',
    'B_refund_code' => 'B-refund-code-receipt.json',
    'C_refund_code' => 'C-refund-code-receipt.json',
    'B_refund_scan' => 'B-refund-scan-receipt.json',
    'C_refund_scan' => 'C-refund-scan-receipt.json',
    'B_refund_payment' => 'B-refund-balance-pay-receipt.json',
    'C_refund_payment' => 'C-refund-balance-pay-receipt.json',
    'B_duplicate' => 'B-duplicate-pay-receipt.json',
    'C_duplicate' => 'C-duplicate-pay-receipt.json',
    'B_old_mismatch_refund' => 'B-pay-refund-receipt.json',
    'B_refund10001_original' => 'B-refund10001-receipt.json',
    'B_refund10001_correction' => 'B-refund10001-correction-receipt.json',
    'C_refund10001' => 'C-refund10001-receipt.json',
    'B_payresult' => 'B-payresult-receipt.json',
    'C_payresult' => 'C-payresult-receipt.json',
];
$receipts = [];
$hashes = [];
foreach ($names as $label => $file) {
    $path = __DIR__ . '/' . $file;
    $raw = file_get_contents($path);
    $decoded = is_string($raw) ? json_decode($raw, true) : null;
    if (!is_array($decoded)) throw new RuntimeException($file . ' is not valid JSON');
    $receipts[$label] = $decoded;
    $hashes[$file] = hash('sha256', $raw);
}
foreach (['B_code', 'C_code', 'B_scan', 'C_retry_scan'] as $label) {
    if (($receipts[$label]['passed'] ?? false) !== true) {
        throw new RuntimeException($label . ' did not pass');
    }
}
$failed = $receipts['C_failed_scan'];
if (($failed['passed'] ?? true) !== false
    || (int)($failed['response_status'] ?? 0) !== 500
    || (int)($failed['meal_order_rows'] ?? -1) !== 0
    || (int)($failed['ai_settlement_rows'] ?? -1) !== 0
    || ($failed['wallet_unchanged'] ?? false) !== true) {
    throw new RuntimeException('Original failed scan is not independently zero-write');
}
if ($receipts['B_code']['response_field_types'] !== $receipts['C_code']['response_field_types']
    || $receipts['B_scan']['response_keys'] !== $receipts['C_retry_scan']['response_keys']
    || $receipts['B_scan']['response_data_types'] !== $receipts['C_retry_scan']['response_data_types']) {
    throw new RuntimeException('Recorded response contract shape differs between B and C');
}
foreach (['B_scan', 'C_retry_scan'] as $label) {
    $r = $receipts[$label];
    if ((int)$r['meal_order_rows'] !== 1 || !$r['pending_meal_source']
        || !$r['wallet_unchanged'] || (int)$r['ai_settlement_rows'] !== 0) {
        throw new RuntimeException($label . ' is not an unpaid one-order scan');
    }
}
$expiry = $receipts['C_exact_expiry'];
if (($expiry['passed'] ?? false) !== true
    || (int)($expiry['prepay_status_before'] ?? -1) !== 2
    || (int)($expiry['prepay_status_after'] ?? -1) !== 3
    || (int)($expiry['meal_status_before'] ?? -1) !== 10
    || (int)($expiry['meal_status_after'] ?? -1) !== 20
    || (int)($expiry['meal_pay_status_after'] ?? -1) !== 10) {
    throw new RuntimeException('Owned C expiry receipt does not match guarded path');
}
foreach (['B_fixture10001', 'C_fixture10001', 'B_recharge10001',
    'C_recharge10001', 'B_refund_code', 'C_refund_code',
    'B_refund_scan', 'C_refund_scan', 'B_refund_payment',
    'C_refund_payment', 'B_duplicate', 'C_duplicate',
    'B_refund10001_correction', 'C_refund10001',
    'B_payresult', 'C_payresult'] as $label) {
    if (($receipts[$label]['passed'] ?? false) !== true) {
        throw new RuntimeException($label . ' did not pass its saved assertions');
    }
}
if ($receipts['B_refund_code']['response_field_types']
        !== $receipts['C_refund_code']['response_field_types']
    || $receipts['B_refund_scan']['response_data_types']
        !== $receipts['C_refund_scan']['response_data_types']
    || $receipts['B_refund_payment']['response_settlement_types']
        !== $receipts['C_refund_payment']['response_settlement_types']) {
    throw new RuntimeException('Recorded 10001 code/scan/payment contract types differ');
}
foreach (['B', 'C'] as $side) {
    $r = $receipts[$side . '_refund_payment'];
    if (bccomp((string)$r['wallet_cash_before'], '0.05', 2) !== 0
        || bccomp((string)$r['wallet_cash_after'], '0.04', 2) !== 0
        || (int)$r['settlement_rows'] !== 1
        || (int)$r['balance_log_rows'] !== 1
        || (int)$r['external_stub_events_delta'] !== 1
        || $r['external_stub_events_new'] !== ['user_sync']) {
        throw new RuntimeException($side . ' owned payment ledger or stub increment differs');
    }
    $dup = $receipts[$side . '_duplicate'];
    if ((int)$dup['response_status'] === 200 || !$dup['wallet_exact_unchanged']
        || !$dup['settlements_exact_unchanged'] || !$dup['balance_logs_exact_unchanged']
        || (int)$dup['stub_events_delta'] !== 0) {
        throw new RuntimeException($side . ' duplicate payment changed ledger');
    }
    $raw = __DIR__ . '/' . $side . '-duplicate-pay-response.raw';
    if (hash_file('sha256', $raw) !== $dup['response_body_sha256']) {
        throw new RuntimeException($side . ' duplicate raw HTTP changed');
    }
    $recharge = $receipts[$side . '_recharge10001'];
    if (hash_file('sha256', __DIR__ . '/' . $side . '-fixture10001-recharge-response.raw')
        !== $recharge['response_body_sha256']) {
        throw new RuntimeException($side . ' recharge raw HTTP changed');
    }
    $refund = $side === 'B' ? $receipts['B_refund10001_original']
        : $receipts['C_refund10001'];
    foreach (['apply', 'agree'] as $phase) {
        if (hash_file('sha256', __DIR__ . '/' . $side . '-refund10001-' . $phase . '.raw')
            !== $refund[$phase . '_response_sha256']) {
            throw new RuntimeException($side . ' refund ' . $phase . ' raw HTTP changed');
        }
    }
    $payResult = $receipts[$side . '_payresult'];
    if ($payResult['response_fields'] !== [
            'orderid' => 'string', 'torderid' => 'string',
            'code' => 'string', 'msg' => 'string',
        ] || (string)$payResult['response_code'] !== '1'
        || !$payResult['request_roundtrip']
        || !$payResult['meal_exact_unchanged']
        || !$payResult['wallet_exact_unchanged']
        || (int)$payResult['settlement_count_before'] !== 2
        || (int)$payResult['settlement_count_after'] !== 2
        || hash_file('sha256', __DIR__ . '/' . $side . '-payresult-response.raw')
            !== $payResult['response_body_sha256']) {
        throw new RuntimeException($side . ' prepay payResult contract/readback differs');
    }
}
$oldMismatch = $receipts['B_old_mismatch_refund'];
if (($oldMismatch['passed'] ?? true) !== false
    || (int)$oldMismatch['apply_code'] !== 0
    || (int)$oldMismatch['agree_code'] !== 2
    || bccomp((string)$oldMismatch['wallet_cash_before'],
        (string)$oldMismatch['wallet_cash_after_agree'], 2) !== 0) {
    throw new RuntimeException('Old mismatched-tenant refund evidence changed');
}
$correction = $receipts['B_refund10001_correction'];
if (hash_file('sha256', __DIR__ . '/B-refund10001-receipt.json')
        !== $correction['original_receipt_sha256']
    || (int)$correction['cash_log_rows_for_owned_ids'] !== 2
    || (int)$correction['consume_log_order_id'] !== 68503
    || (int)$correction['refund_log_order_id'] !== 325) {
    throw new RuntimeException('B pure refund correction not linked to original receipt');
}
echo json_encode(['status' => 'verified_from_saved_receipts',
    'code_contract_types_equal' => true,
    'scan_recorded_keys_and_data_types_equal' => true,
    'C_original_failure_zero_write' => true,
    'successful_pending_orders' => 2,
    'C_exact_owned_expiry' => true,
    'B_C_10001_recharge_payment_refund' => true,
    'B_C_duplicate_payment_rejected_without_write' => true,
    'B_C_prepay_payResult_readback' => true,
    'old_B_mismatched_tenant_refund_retained' => true,
    'sha256' => $hashes], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . PHP_EOL;
