<?php

declare(strict_types=1);

$marker = (string)getenv('POC_MARKER');
$orderId = (int)getenv('POC_ORDER_ID');
$dialect = (string)getenv('POC_DIALECT');
$baseUrl = rtrim((string)getenv('POC_BASE_URL'), '/');
$root = (string)getenv('POC_APP_ROOT');
if (!preg_match('/^CDXPARMOB[A-F0-9]{8}$/D', $marker) || $orderId <= 0
    || !in_array($dialect, ['mysql', 'dm'], true) || $baseUrl === ''
    || !is_file($root . '/application/base/Security.php')) {
    throw new RuntimeException('Explicit synthetic refund target and isolated runtime required');
}
if ($dialect === 'mysql') {
    $config = require '/workspace/zhct/zhctproject/store/application/config/local/database.php';
    foreach (['' => $config, 'AI_' => $config['ai_zhct']] as $prefix => $part) {
        foreach (['hostname' => 'HOST', 'hostport' => 'PORT', 'database' => 'SCHEMA',
            'username' => 'USER', 'password' => 'PASSWORD'] as $source => $target) {
            putenv('POC_' . $prefix . $target . '='
                . (string)($part[$source] ?? ($target === 'PORT' ? 3306 : '')));
        }
    }
}
foreach (['HOST', 'PORT', 'SCHEMA', 'USER', 'PASSWORD',
    'AI_HOST', 'AI_PORT', 'AI_SCHEMA', 'AI_USER', 'AI_PASSWORD'] as $part) {
    if (getenv('POC_' . $part) === false) {
        throw new RuntimeException('Selected test database environment incomplete');
    }
}
$boundary = json_decode((string)file_get_contents($baseUrl . '/__poc_boundary'), true);
if (empty($boundary['external_stubs']) || empty($boundary['redis_isolated'])
    || !empty($boundary['refund_fault']) || !empty($boundary['account_fault'])) {
    throw new RuntimeException('Isolated refund boundary unavailable');
}
$connect = static function (string $prefix) use ($dialect): PDO {
    $host = getenv('POC_' . $prefix . 'HOST');
    $port = getenv('POC_' . $prefix . 'PORT');
    $schema = getenv('POC_' . $prefix . 'SCHEMA');
    $dsn = $dialect === 'dm' ? "dm:host=$host;port=$port;schema=$schema"
        : "mysql:host=$host;port=$port;dbname=$schema;charset=utf8mb4";
    return new PDO($dsn, getenv('POC_' . $prefix . 'USER'),
        getenv('POC_' . $prefix . 'PASSWORD'),
        [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
};
$store = $connect('');
$ai = $connect('AI_');
$table = static function (string $prefix, string $name) use ($dialect): string {
    $value = $prefix . $name;
    return $dialect === 'dm' ? strtoupper($value) : $value;
};
$sOrder = $table('ydy_', 'meal_order');
$sRefund = $table('ydy_', 'meal_order_refund');
$sUser = $table('ydy_', 'user');
$aUser = $table('yoshop_', 'user');
$aSettlement = $table('yoshop_', 'account_settlement');
$aBalanceLog = $table('yoshop_', 'user_balance_log');
$read = static function (PDO $pdo, string $sql, array $args = []): array {
    $q = $pdo->prepare($sql);
    $q->execute($args);
    return array_change_key_case((array)$q->fetch(PDO::FETCH_ASSOC));
};
$count = static function (PDO $pdo, string $sql, array $args = []): int {
    $q = $pdo->prepare($sql);
    $q->execute($args);
    return (int)$q->fetchColumn();
};
$cents = static function ($money): int {
    $value = (string)$money;
    if (!preg_match('/^(-?)(\d+)(?:\.(\d{1,2}))?$/', $value, $m)) {
        throw new RuntimeException('Unexpected money representation');
    }
    return ($m[1] === '-' ? -1 : 1) * ((int)$m[2] * 100
        + (int)str_pad($m[3] ?? '', 2, '0'));
};
$assert = static function (bool $ok, string $message): void {
    if (!$ok) throw new RuntimeException($message);
};
$order = $read($store, 'SELECT ID,ORDER_NO,USER_ID,REMARK,PAY_PRICE,PAY_STATUS,'
    . 'PAY_METHOD,PAY_TYPE,ORDER_STATUS,REFUND_STATUS FROM ' . $sOrder . ' WHERE ID=?', [$orderId]);
$linked = $read($store, 'SELECT ID,UUID,ACCOUNT,TYPE,AI_USER_ID FROM ' . $sUser
    . ' WHERE ID=?', [(int)($order['user_id'] ?? 0)]);
$aiId = (int)($linked['ai_user_id'] ?? 0);
$wallet = $read($ai, 'SELECT USER_ID,NICK_NAME,BALANCE,SUBSIDY_BALANCE,GIFT_BALANCE FROM '
    . $aUser . ' WHERE USER_ID=?', [$aiId]);
$originalSettlement = $read($ai, 'SELECT SETTLEMENT_ID,AMOUNT,CASH_AMOUNT,'
    . 'SUBSIDY_AMOUNT,GIFT_AMOUNT,STATUS FROM ' . $aSettlement
    . " WHERE BIZ_ORDER_NO=? AND BIZ_TYPE='consume'",
    [(string)($order['order_no'] ?? '')]);
$payCents = $cents($order['pay_price'] ?? '0');
$cashPaid = $cents($originalSettlement['cash_amount'] ?? '0');
$subsidyPaid = $cents($originalSettlement['subsidy_amount'] ?? '0');
$giftPaid = $cents($originalSettlement['gift_amount'] ?? '0');
$beforeCents = $cents($wallet['balance'] ?? '0');
$assert($order !== [] && $order['remark'] === $marker
    && (int)$order['pay_status'] === 20 && (int)$order['order_status'] === 30
    && (int)$order['refund_status'] === 0 && $order['pay_method'] === 'balance'
    && (int)$order['pay_type'] === 10 && $payCents > 0
    && $linked['account'] === $marker
    && strpos((string)$linked['uuid'], 'CDXPARMOB-') === 0
    && $wallet['nick_name'] === $marker && (int)$wallet['user_id'] === $aiId
    && (int)$originalSettlement['status'] === 20
    && $cashPaid + $subsidyPaid + $giftPaid === $payCents
    && $cashPaid === $payCents && $subsidyPaid === 0 && $giftPaid === 0
    && $beforeCents === 10000 - $payCents
    && $count($store, "SELECT COUNT(*) FROM $sRefund WHERE MEAL_ORDER_ID=?", [$orderId]) === 0
    && $count($ai, "SELECT COUNT(*) FROM $aBalanceLog WHERE USER_ID=? AND ORDER_ID=?",
        [$aiId, $orderId]) === 1,
    'Synthetic order is not in expected refundable local-cash state; no request sent');

require_once $root . '/application/base/Security.php';
$adminToken = \app\base\Security::encrypt(implode("\t", [
    (string)$linked['id'], (string)$linked['uuid'], $marker, '0', '', '', $marker,
]));
$post = static function (string $route, array $form, ?string $token) use ($baseUrl): array {
    $headers = "Content-Type: application/x-www-form-urlencoded\r\n";
    if ($token !== null) $headers .= 'token: ' . $token . "\r\n";
    $context = stream_context_create(['http' => [
        'method' => 'POST', 'header' => $headers,
        'content' => http_build_query($form, '', '&', PHP_QUERY_RFC3986),
        'timeout' => 30, 'ignore_errors' => true,
    ]]);
    $body = file_get_contents($baseUrl . $route, false, $context);
    $statusLine = $http_response_header[0] ?? '';
    $json = is_string($body) ? json_decode($body, true) : null;
    if (!is_array($json)) throw new RuntimeException('Refund HTTP response not JSON: '
        . $statusLine);
    return ['http' => (int)(preg_match('/HTTP\/\S+\s+(\d+)/', $statusLine, $m)
        ? $m[1] : 0), 'body' => $json];
};
$unauth = $post('/p/mealOrder/refund', ['order_id' => $orderId,
    'refund_amount' => $order['pay_price'], 'apply_desc' => $marker], null);
$assert((int)($unauth['body']['code'] ?? 0) !== 0
    && $count($store, "SELECT COUNT(*) FROM $sRefund WHERE MEAL_ORDER_ID=?", [$orderId]) === 0,
    'Unauthenticated refund application accepted');

$originalType = (int)$linked['type'];
$refundId = 0;
$restoreType = $originalType !== 0;
if ($restoreType) {
    $grant = $store->prepare("UPDATE $sUser SET TYPE=0 WHERE ID=? AND UUID=? AND ACCOUNT=?");
    $grant->execute([(int)$linked['id'], $linked['uuid'], $marker]);
    $assert($grant->rowCount() === 1, 'Temporary synthetic admin grant not exact');
}
try {
    $apply = $post('/p/mealOrder/refund', ['order_id' => $orderId,
        'refund_amount' => $order['pay_price'], 'apply_desc' => $marker], $adminToken);
    $refundId = (int)($apply['body']['data']['refund_id'] ?? 0);
    $refund = $read($store, 'SELECT ID,ORDER_NO,MEAL_ORDER_ID,REFUND_AMOUNT,REFUND_STATUS'
        . " FROM $sRefund WHERE ID=? AND MEAL_ORDER_ID=?", [$refundId, $orderId]);
    $orderApplied = $read($store, 'SELECT REFUND_STATUS,REFUND_AMOUNT FROM '
        . $sOrder . ' WHERE ID=?', [$orderId]);
    $assert($apply['http'] === 200 && (int)($apply['body']['code'] ?? -1) === 0
        && $refundId > 0 && (int)$refund['refund_status'] === 1
        && (int)$orderApplied['refund_status'] === 1
        && $cents($refund['refund_amount']) === $payCents,
        'Formal refund application/readback failed: '
            . json_encode(['code' => $apply['body']['code'] ?? null,
                'message' => $apply['body']['message'] ?? null,
                'refund_id' => $refundId], JSON_UNESCAPED_UNICODE));
    $agree = $post('/p/mealOrder/refundAgree', ['refund_id' => $refundId], $adminToken);
    $orderAfter = $read($store, 'SELECT REFUND_STATUS,REFUND_AMOUNT,CASH_REFUND_AMOUNT,'
        . 'SUBSIDY_REFUND_AMOUNT,GIFT_REFUND_AMOUNT FROM ' . $sOrder . ' WHERE ID=?',
        [$orderId]);
    $refundAfter = $read($store, 'SELECT REFUND_STATUS,ACCOUNT_SETTLEMENT_ID FROM '
        . $sRefund . ' WHERE ID=?', [$refundId]);
    $walletAfter = $read($ai, 'SELECT BALANCE,SUBSIDY_BALANCE,GIFT_BALANCE FROM '
        . $aUser . ' WHERE USER_ID=?', [$aiId]);
    $refundSettlement = $read($ai, 'SELECT SETTLEMENT_ID,AMOUNT,CASH_AMOUNT,'
        . 'SUBSIDY_AMOUNT,GIFT_AMOUNT,STATUS FROM ' . $aSettlement
        . " WHERE REFUND_NO=? AND BIZ_TYPE='refund'", [(string)$refund['order_no']]);
    $cashLogAfter = $count($ai, "SELECT COUNT(*) FROM $aBalanceLog"
        . ' WHERE USER_ID=? AND ORDER_ID IN (?,?)', [$aiId, $orderId, $refundId]);
    $refundCashLog = $read($ai, 'SELECT MONEY,BALANCE_AFTER FROM ' . $aBalanceLog
        . ' WHERE USER_ID=? AND ORDER_ID=?', [$aiId, $refundId]);
    $assert($agree['http'] === 200 && (int)($agree['body']['code'] ?? -1) === 0
        && (int)$orderAfter['refund_status'] === 3
        && (int)$refundAfter['refund_status'] === 2
        && (int)$refundAfter['account_settlement_id'] > 0
        && (int)$refundSettlement['settlement_id']
            === (int)$refundAfter['account_settlement_id']
        && (int)$refundSettlement['status'] === 20
        && $cents($orderAfter['refund_amount']) === $payCents
        && $cents($orderAfter['cash_refund_amount']) === $cashPaid
        && $cents($orderAfter['subsidy_refund_amount']) === 0
        && $cents($orderAfter['gift_refund_amount']) === 0
        && $cents($refundSettlement['amount']) === $payCents
        && $cents($refundSettlement['cash_amount']) === $cashPaid
        && $cents($refundSettlement['subsidy_amount']) === 0
        && $cents($refundSettlement['gift_amount']) === 0
        && $cents($walletAfter['balance']) === $beforeCents + $cashPaid
        && $cashLogAfter === 2
        && $cents($refundCashLog['money'] ?? '0') === $cashPaid
        && $cents($refundCashLog['balance_after'] ?? '0') === $beforeCents + $cashPaid,
        'Formal refund approval/ledger readback failed: '
            . json_encode(['code' => $agree['body']['code'] ?? null,
                'message' => $agree['body']['message'] ?? null,
                'refund_id' => $refundId], JSON_UNESCAPED_UNICODE));
    $repeat = $post('/p/mealOrder/refundAgree', ['refund_id' => $refundId], $adminToken);
    $walletRepeat = $read($ai, "SELECT BALANCE FROM $aUser WHERE USER_ID=?", [$aiId]);
    $refundSettlementCount = $count($ai,
        "SELECT COUNT(*) FROM $aSettlement WHERE REFUND_NO=? AND BIZ_TYPE='refund'",
        [(string)$refund['order_no']]);
    $cashLogRepeat = $count($ai, "SELECT COUNT(*) FROM $aBalanceLog"
        . ' WHERE USER_ID=? AND ORDER_ID IN (?,?)', [$aiId, $orderId, $refundId]);
    $assert((int)($repeat['body']['code'] ?? 0) !== 0
        && $cents($walletRepeat['balance']) === $beforeCents + $cashPaid
        && $refundSettlementCount === 1 && $cashLogRepeat === 2,
        'Repeated refund approval changed wallet or ledger');
    echo json_encode([
        'dialect' => $dialect, 'status' => 'passed', 'marker' => $marker,
        'order_id' => $orderId, 'refund_id' => $refundId,
        'refund_cents' => $payCents, 'wallet_before_cents' => $beforeCents,
        'wallet_after_cents' => $cents($walletAfter['balance']),
        'refund_settlement_count' => $refundSettlementCount,
        'cash_log_count_after_refund' => $cashLogRepeat,
        'response_contract' => [
            'unauth_code' => $unauth['body']['code'] ?? null,
            'apply_code' => $apply['body']['code'],
            'apply_message' => $apply['body']['message'] ?? null,
            'apply_keys' => array_keys((array)$apply['body']['data']),
            'agree_code' => $agree['body']['code'],
            'agree_message' => $agree['body']['message'] ?? null,
            'repeat_code' => $repeat['body']['code'] ?? null,
            'repeat_message' => $repeat['body']['message'] ?? null,
        ],
    ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . PHP_EOL;
} finally {
    if ($restoreType) {
        $restore = $store->prepare("UPDATE $sUser SET TYPE=? WHERE ID=? AND UUID=? AND ACCOUNT=?");
        $restore->execute([$originalType, (int)$linked['id'], $linked['uuid'], $marker]);
        $check = $read($store, "SELECT TYPE FROM $sUser WHERE ID=?", [(int)$linked['id']]);
        if ((int)($check['type'] ?? -1) !== $originalType) {
            throw new RuntimeException('Synthetic admin permission not restored');
        }
    }
    fwrite(STDERR, 'Synthetic refund audit retained: marker=' . $marker
        . ' order_id=' . $orderId . ' refund_id=' . $refundId . PHP_EOL);
}
