<?php

declare(strict_types=1);

$lane = $argv[1] ?? '';
if (!in_array($lane, ['B', 'C'], true)) exit(2);
$root = '/tmp/cdx-prepay-code-scan-20261012-' . $lane . '-store';
$marker = $lane === 'B' ? 'CDXPPREF12B01-O1' : 'CDXPPREF12C01-O1';
$prepayId = $lane === 'B' ? 26 : 5;
$mealId = $lane === 'B' ? 68503 : 23666;
$deviceId = $lane === 'B' ? 232 : 178;
$aiUserId = $lane === 'B' ? 46921 : 1936;
$dialect = $lane === 'B' ? 'mysql' : 'dm';
$pid = (int)file_get_contents($root . '/private-http.pid');
if (strpos((string)file_get_contents('/proc/' . $pid . '/cmdline'), $root . '/public') === false) {
    throw new RuntimeException('Wrong private Store owner');
}
foreach (explode("\0", (string)file_get_contents('/proc/' . $pid . '/environ')) as $pair) {
    $parts = explode('=', $pair, 2);
    if (count($parts) === 2 && strpos($parts[0], 'POC_') === 0) putenv($pair);
}
if (getenv('POC_DIALECT') !== $dialect) throw new RuntimeException('Wrong dialect');
$boundary = json_decode((string)file_get_contents('http://127.0.0.1:'
    . ($lane === 'B' ? 19131 : 19132) . '/__poc_boundary'), true);
if (empty($boundary['external_stubs']) || empty($boundary['redis_isolated'])
    || !empty($boundary['real_queue'])) throw new RuntimeException('Private external boundary unavailable');
$cfg = require $root . '/application/database.php';
$connect = static function (array $c) use ($dialect): PDO {
    $dsn = $dialect === 'dm'
        ? 'dm:host=' . $c['hostname'] . ';port=' . $c['hostport'] . ';schema=' . $c['database']
        : 'mysql:host=' . $c['hostname'] . ';port=' . ($c['hostport'] ?? 3306)
            . ';dbname=' . $c['database'] . ';charset=utf8mb4';
    return new PDO($dsn, $c['username'], $c['password'],
        [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
};
$store = $connect($cfg);
$ai = $connect($cfg['ai_zhct']);
$table = static function (string $name, bool $isAi = false) use ($dialect): string {
    $prefix = $isAi ? 'yoshop_' : 'ydy_';
    return $dialect === 'dm' ? strtoupper($prefix . $name) : $prefix . $name;
};
$one = static function (PDO $db, string $sql, array $params = []): array {
    $stmt = $db->prepare($sql);
    $stmt->execute($params);
    return array_change_key_case($stmt->fetch(PDO::FETCH_ASSOC) ?: [], CASE_LOWER);
};
$prepay = $one($store, 'SELECT ID,DEVICE_ORDER_NO,MACHID,MEAL_ORDER_ID,USER_ID,'
    . 'PREPAY_STATUS,SHIP_STATUS,RAW_REQUEST_C,UPDATE_BY FROM '
    . $table('prepay_order') . ' WHERE ID=?', [$prepayId]);
$meal = $one($store, 'SELECT ID,ORDER_NO,PAY_STATUS,ORDER_STATUS,REFUND_STATUS,REFUND_AMOUNT FROM '
    . $table('meal_order') . ' WHERE ID=?', [$mealId]);
$device = $one($store, 'SELECT ID,SN,TYPE,DEL_FLAG FROM '
    . $table('equipment') . ' WHERE ID=?', [$deviceId]);
$wallet = $one($ai, 'SELECT BALANCE,SUBSIDY_BALANCE,GIFT_BALANCE FROM '
    . $table('user', true) . ' WHERE USER_ID=?', [$aiUserId]);
$settlement = $one($ai, 'SELECT COUNT(*) AS N FROM '
    . $table('account_settlement', true) . ' WHERE BIZ_ORDER_NO=?',
    [(string)($meal['order_no'] ?? '')]);
if ((int)($prepay['id'] ?? 0) !== $prepayId
    || (string)($prepay['device_order_no'] ?? '') !== $marker
    || (int)($prepay['meal_order_id'] ?? 0) !== $mealId
    || (int)($prepay['prepay_status'] ?? -1) !== 1
    || (int)($meal['pay_status'] ?? -1) !== 20
    || (int)($meal['order_status'] ?? -1) !== 30
    || (int)($meal['refund_status'] ?? -1) !== 3
    || bccomp((string)($wallet['balance'] ?? '-1'), '0.05', 2) !== 0
    || (int)($settlement['n'] ?? 0) !== 2
    || (int)($device['id'] ?? 0) !== $deviceId
    || (int)($device['type'] ?? 0) !== 60
    || (int)($device['del_flag'] ?? -1) !== 0
    || (string)($device['sn'] ?? '') !== 'CDXPPFORM11_M1') {
    throw new RuntimeException('Only own settled/refunded prepay can query result');
}
$keyRows = $store->prepare('SELECT CONFIG_VALUE FROM ' . $table('config')
    . " WHERE CONFIG_KEY='coffee_machine_appkey' AND STATUS=1");
$keyRows->execute();
$keys = $keyRows->fetchAll(PDO::FETCH_COLUMN);
$keys = array_values(array_unique(array_map('trim', array_map('strval', $keys))));
if (count($keys) !== 1 || $keys[0] === '') throw new RuntimeException('Exactly one active app key required');
if (getenv('POC_DRY_RUN') === '1') {
    echo json_encode(['lane' => $lane, 'prepay_id' => $prepayId,
        'status' => 1, 'meal_paid_and_refunded' => true,
        'cash_wallet' => (string)$wallet['balance'],
        'no_HTTP_or_DML' => true]) . PHP_EOL;
    exit(0);
}
$attemptPath = $root . '/payresult-attempt.json';
$rawPath = $root . '/payresult-response.raw';
$receiptPath = $root . '/payresult-receipt.json';
if (is_file($attemptPath) || is_file($rawPath) || is_file($receiptPath)) {
    throw new RuntimeException('Pay result already queried for own fixture');
}
$timestamp = (string)time();
$randstr = bin2hex(random_bytes(16));
$signParts = [$keys[0], $timestamp, $randstr];
sort($signParts, SORT_STRING);
$form = ['machid' => (string)$device['sn'], 'orderid' => $marker,
    'torderid' => (string)$prepayId,
    'timestamp' => $timestamp, 'randstr' => $randstr,
    'sign' => sha1(implode('', $signParts))];
$body = http_build_query($form, '', '&', PHP_QUERY_RFC1738);
$attempt = ['lane' => $lane, 'marker' => $marker,
    'path' => '/api/prepayOrder/payResult',
    'body_sha256' => hash('sha256', $body),
    'prepay_id' => $prepayId, 'meal_id' => $mealId,
    'before_prepay_status' => 1, 'before_settlement_rows' => 2,
    'before_cash_balance' => (string)$wallet['balance'], 'at' => date('c')];
$handle = fopen($attemptPath, 'xb');
if (!$handle) throw new RuntimeException('Cannot lock pay result request');
fwrite($handle, json_encode($attempt, JSON_UNESCAPED_SLASHES));
fclose($handle);
chmod($attemptPath, 0600);
$context = stream_context_create(['http' => [
    'method' => 'POST', 'ignore_errors' => true, 'timeout' => 30,
    'header' => "Content-Type: application/x-www-form-urlencoded\r\n"
        . "Host: prepay.code-scan.invalid\r\n",
    'content' => $body,
]]);
$wire = file_get_contents('http://127.0.0.1:' . ($lane === 'B' ? 19131 : 19132)
    . '/api/prepayOrder/payResult', false, $context);
$raw = is_string($wire) ? $wire : '';
$handle = fopen($rawPath, 'xb');
if (!$handle) throw new RuntimeException('Cannot preserve pay result response');
fwrite($handle, $raw);
fclose($handle);
chmod($rawPath, 0600);
$http = 0;
foreach (($http_response_header ?? []) as $header) {
    if (preg_match('/^HTTP\/\S+ (\d{3})/', $header, $match)) $http = (int)$match[1];
}
$response = json_decode($raw, true);
$afterPrepay = $one($store, 'SELECT PREPAY_STATUS,SHIP_STATUS,RAW_REQUEST_C,UPDATE_BY FROM '
    . $table('prepay_order') . ' WHERE ID=?', [$prepayId]);
$afterMeal = $one($store, 'SELECT PAY_STATUS,ORDER_STATUS,REFUND_STATUS,REFUND_AMOUNT FROM '
    . $table('meal_order') . ' WHERE ID=?', [$mealId]);
$afterWallet = $one($ai, 'SELECT BALANCE,SUBSIDY_BALANCE,GIFT_BALANCE FROM '
    . $table('user', true) . ' WHERE USER_ID=?', [$aiUserId]);
$afterSettlement = $one($ai, 'SELECT COUNT(*) AS N FROM '
    . $table('account_settlement', true) . ' WHERE BIZ_ORDER_NO=?',
    [(string)$meal['order_no']]);
$receipt = ['lane' => $lane, 'marker' => $marker,
    'http_status' => $http,
    'response_json' => is_array($response),
    'response_fields' => is_array($response) ? array_map('gettype', $response) : [],
    'response_code' => $response['code'] ?? null,
    'response_orderid_match' => (string)($response['orderid'] ?? '') === $marker,
    'response_torderid_match' => (string)($response['torderid'] ?? '') === (string)$prepayId,
    'response_body_sha256' => hash('sha256', $raw),
    'response_raw_file' => basename($rawPath),
    'prepay_status_before' => (int)$prepay['prepay_status'],
    'prepay_status_after' => (int)($afterPrepay['prepay_status'] ?? -1),
    'request_roundtrip' => json_decode((string)($afterPrepay['raw_request_c'] ?? ''), true) === $form,
    'meal_exact_unchanged' => (int)($afterMeal['pay_status'] ?? -1) === (int)$meal['pay_status']
        && (int)($afterMeal['order_status'] ?? -1) === (int)$meal['order_status']
        && (int)($afterMeal['refund_status'] ?? -1) === (int)$meal['refund_status']
        && bccomp((string)($afterMeal['refund_amount'] ?? '-1'),
            (string)$meal['refund_amount'], 2) === 0,
    'wallet_exact_unchanged' => $wallet === $afterWallet,
    'settlement_count_before' => (int)$settlement['n'],
    'settlement_count_after' => (int)($afterSettlement['n'] ?? -1)];
$receipt['passed'] = $http === 200 && $receipt['response_json']
    && (string)$receipt['response_code'] === '1'
    && $receipt['response_orderid_match'] && $receipt['response_torderid_match']
    && $receipt['prepay_status_after'] === 1
    && $receipt['request_roundtrip'] && $receipt['meal_exact_unchanged']
    && $receipt['wallet_exact_unchanged']
    && $receipt['settlement_count_before'] === 2
    && $receipt['settlement_count_after'] === 2;
file_put_contents($receiptPath, json_encode($receipt,
    JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), LOCK_EX);
chmod($receiptPath, 0600);
echo json_encode($receipt, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . PHP_EOL;
exit($receipt['passed'] ? 0 : 1);
