<?php

declare(strict_types=1);

$marker = (string)getenv('POC_MARKER');
$dialect = (string)getenv('POC_DIALECT');
$baseUrl = rtrim((string)getenv('POC_BASE_URL'), '/');
$root = (string)getenv('POC_APP_ROOT');
if (!preg_match('/^CDXPAY[A-F0-9]{8}$/D', $marker)
    || !in_array($dialect, ['mysql', 'dm'], true)
    || $baseUrl === '' || !is_file($root . '/application/base/Security.php')) {
    exit(2);
}
$boundary = json_decode((string)file_get_contents($baseUrl . '/__poc_boundary'), true);
if (empty($boundary['external_stubs']) || empty($boundary['redis_isolated'])) {
    throw new RuntimeException('Refund isolated external boundary unavailable');
}
$connect = static function (bool $ai) use ($dialect): PDO {
    $prefix = $ai ? 'POC_AI_' : 'POC_';
    $host = getenv($prefix . 'HOST');
    $port = getenv($prefix . 'PORT');
    $schema = getenv($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($prefix . 'USER'), getenv($prefix . 'PASSWORD'),
        [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
};
$store = $connect(false);
$ai = $connect(true);
$s = static function (string $name) use ($dialect): string {
    return $dialect === 'dm' ? 'YDY_' . strtoupper($name) : 'ydy_' . $name;
};
$a = static function (string $name) use ($dialect): string {
    return $dialect === 'dm' ? 'YOSHOP_' . strtoupper($name) : 'yoshop_' . $name;
};
$read = static function (PDO $pdo, string $sql, array $params = []): array {
    $statement = $pdo->prepare($sql);
    $statement->execute($params);
    return array_change_key_case($statement->fetch(PDO::FETCH_ASSOC) ?: [], CASE_LOWER);
};
$order = $read($store, 'SELECT ID,ORDER_NO,PAY_PRICE,ORDER_STATUS,REFUND_STATUS,'
    . 'USER_ID,PAY_TYPE FROM ' . $s('meal_order') . ' WHERE MSGID=?', [$marker]);
if (!$order || (int)$order['order_status'] !== 30
    || (int)$order['refund_status'] !== 0
    || bccomp((string)$order['pay_price'], '0.00', 2) <= 0) {
    throw new RuntimeException('Synthetic paid order is not refundable');
}
$orderId = (int)$order['id'];
$orderNo = (string)$order['order_no'];
$payPrice = (string)$order['pay_price'];
$linked = $read($store, 'SELECT AI_USER_ID,UUID,ACCOUNT,TYPE FROM ' . $s('user')
    . ' WHERE ID=?', [(int)$order['user_id']]);
$aiUserId = (int)($linked['ai_user_id'] ?? 0);
if ((string)($linked['account'] ?? '') !== $marker
    || strpos((string)($linked['uuid'] ?? ''), 'CDXUSER-') !== 0) {
    throw new RuntimeException('Refund admin identity is not a synthetic test user');
}
$walletBefore = $read($ai, 'SELECT BALANCE,SUBSIDY_BALANCE,GIFT_BALANCE FROM ' . $a('user')
    . ' WHERE USER_ID=?', [$aiUserId]);
$readLocalSubsidy = static function () use ($read, $ai, $a, $aiUserId): string {
    $time = date('Y-m-d H:i:s');
    $row = $read($ai, 'SELECT COALESCE(SUM(MONEY),0) AS TOTAL FROM '
        . $a('user_subsidy') . ' WHERE USER_ID=? AND IS_DELETE=0'
        . ' AND EXPIRATION_START_TIME<=? AND EXPIRATION_END_TIME>=?',
        [$aiUserId, $time, $time]);
    return (string)($row['total'] ?? '0');
};
$localSubsidyBefore = $readLocalSubsidy();
$paidSplit = $read($ai, 'SELECT CASH_AMOUNT,SUBSIDY_AMOUNT,GIFT_AMOUNT FROM '
    . $a('account_settlement') . " WHERE BIZ_ORDER_NO=? AND BIZ_TYPE='consume'",
    [$orderNo]);
$cashPaid = (string)($paidSplit['cash_amount'] ?? '0');
$subsidyPaid = (string)($paidSplit['subsidy_amount'] ?? '0');
$giftPaid = (string)($paidSplit['gift_amount'] ?? '0');
if ($aiUserId <= 0 || !$walletBefore || !$paidSplit
    || bccomp(bcadd(bcadd($cashPaid, $subsidyPaid, 2), $giftPaid, 2),
        $payPrice, 2) !== 0) {
    throw new RuntimeException('Refund fixture is not a settled local-wallet payment');
}
require_once $root . '/application/base/Security.php';
$adminToken = \app\base\Security::encrypt(implode("\t", [
    (string)$order['user_id'], (string)$linked['uuid'],
    $marker, '0', '', '', $marker,
]));
$post = static function (string $route, array $form) use ($baseUrl, $adminToken): array {
    $context = stream_context_create(['http' => [
        'method' => 'POST',
        'header' => "Content-Type: application/x-www-form-urlencoded\r\n"
            . 'token: ' . $adminToken . "\r\n",
        'content' => http_build_query($form, '', '&', PHP_QUERY_RFC3986),
        'timeout' => 30, 'ignore_errors' => true,
    ]]);
    $body = file_get_contents($baseUrl . $route, false, $context);
    $response = is_string($body) ? json_decode($body, true) : null;
    if (!is_array($response)) throw new RuntimeException('Refund HTTP response not JSON');
    return $response;
};
$originalType = (int)$linked['type'];
$restoreType = $originalType !== 0;
if ($restoreType) {
    $grant = $store->prepare('UPDATE ' . $s('user')
        . ' SET TYPE=0 WHERE ID=? AND UUID=? AND ACCOUNT=?');
    $grant->execute([(int)$order['user_id'], (string)$linked['uuid'], $marker]);
    if ($grant->rowCount() !== 1) {
        throw new RuntimeException('Synthetic refund admin grant failed');
    }
}
try {
$apply = $post('/p/mealOrder/refund', [
    'order_id' => $orderId, 'refund_amount' => $payPrice,
    'apply_desc' => $marker,
]);
$refundId = (int)($apply['data']['refund_id'] ?? 0);
$refund = $read($store, 'SELECT ID,ORDER_NO,REFUND_AMOUNT,REFUND_STATUS FROM '
    . $s('meal_order_refund') . ' WHERE ID=? AND MEAL_ORDER_ID=?',
    [$refundId, $orderId]);
$orderApplied = $read($store, 'SELECT REFUND_STATUS,REFUND_AMOUNT FROM '
    . $s('meal_order') . ' WHERE ID=?', [$orderId]);
if ((int)($apply['code'] ?? -1) !== 0 || $refundId <= 0
    || (int)($refund['refund_status'] ?? 0) !== 1
    || (int)($orderApplied['refund_status'] ?? 0) !== 1
    || bccomp((string)($refund['refund_amount'] ?? '0'), $payPrice, 2) !== 0) {
    throw new RuntimeException('Formal refund apply/readback failed: '
        . json_encode(['code' => $apply['code'] ?? null,
            'message' => $apply['message'] ?? null,
            'refund_id' => $refundId], JSON_UNESCAPED_UNICODE));
}
$agree = $post('/p/mealOrder/refundAgree', ['refund_id' => $refundId]);
$orderAfter = $read($store, 'SELECT REFUND_STATUS,REFUND_AMOUNT,CASH_REFUND_AMOUNT,'
    . 'SUBSIDY_REFUND_AMOUNT,GIFT_REFUND_AMOUNT FROM ' . $s('meal_order')
    . ' WHERE ID=?', [$orderId]);
$refundAfter = $read($store, 'SELECT REFUND_STATUS,ACCOUNT_SETTLEMENT_ID '
    . 'FROM ' . $s('meal_order_refund') . ' WHERE ID=?', [$refundId]);
$walletAfter = $read($ai, 'SELECT BALANCE,SUBSIDY_BALANCE,GIFT_BALANCE FROM ' . $a('user')
    . ' WHERE USER_ID=?', [$aiUserId]);
$localSubsidyAfter = $readLocalSubsidy();
$refundedSplit = $read($ai, 'SELECT CASH_AMOUNT,SUBSIDY_AMOUNT,GIFT_AMOUNT FROM '
    . $a('account_settlement') . " WHERE REFUND_NO=? AND BIZ_TYPE='refund'",
    [(string)$refund['order_no']]);
if ((int)($agree['code'] ?? -1) !== 0
    || (int)($orderAfter['refund_status'] ?? 0) !== 3
    || (int)($refundAfter['refund_status'] ?? 0) !== 2
    || (int)($refundAfter['account_settlement_id'] ?? 0) <= 0
    || bccomp((string)($orderAfter['refund_amount'] ?? '0'), $payPrice, 2) !== 0
    || bccomp((string)($orderAfter['cash_refund_amount'] ?? '0'), $cashPaid, 2) !== 0
    || bccomp((string)($orderAfter['subsidy_refund_amount'] ?? '0'), $subsidyPaid, 2) !== 0
    || bccomp((string)($orderAfter['gift_refund_amount'] ?? '0'), $giftPaid, 2) !== 0
    || bccomp((string)($refundedSplit['cash_amount'] ?? '0'), $cashPaid, 2) !== 0
    || bccomp((string)($refundedSplit['subsidy_amount'] ?? '0'), $subsidyPaid, 2) !== 0
    || bccomp((string)($refundedSplit['gift_amount'] ?? '0'), $giftPaid, 2) !== 0
    || bccomp((string)($walletAfter['balance'] ?? '0'),
        bcadd((string)($walletBefore['balance'] ?? '0'), $cashPaid, 2), 2) !== 0
    || bccomp($localSubsidyAfter,
        bcadd($localSubsidyBefore, $subsidyPaid, 2), 2) !== 0
    || bccomp((string)($walletAfter['gift_balance'] ?? '0'),
        bcadd((string)($walletBefore['gift_balance'] ?? '0'), $giftPaid, 2), 2) !== 0) {
    throw new RuntimeException('Formal refund approval/wallet readback failed: '
        . json_encode(['code' => $agree['code'] ?? null,
            'message' => $agree['message'] ?? null,
            'order_refund_status' => $orderAfter['refund_status'] ?? null,
            'refund_status' => $refundAfter['refund_status'] ?? null,
            'wallet_after' => $walletAfter], JSON_UNESCAPED_UNICODE));
}
$repeatAgree = $post('/p/mealOrder/refundAgree', ['refund_id' => $refundId]);
$walletRepeat = $read($ai, 'SELECT BALANCE,SUBSIDY_BALANCE,GIFT_BALANCE FROM ' . $a('user')
    . ' WHERE USER_ID=?', [$aiUserId]);
if ((int)($repeatAgree['code'] ?? 0) === 0 || $walletRepeat !== $walletAfter
    || bccomp($readLocalSubsidy(), $localSubsidyAfter, 2) !== 0) {
    throw new RuntimeException('Repeated refund approval changed wallet');
}
echo json_encode(['dialect' => $dialect, 'status' => 'passed',
    'marker' => $marker, 'order_id' => $orderId, 'refund_id' => $refundId,
    'refund_amount' => $payPrice,
    'refund_split' => ['cash' => $cashPaid, 'subsidy' => $subsidyPaid,
        'gift' => $giftPaid],
    'wallet_components_restored' => true,
    'repeat_approval_rejected' => true],
    JSON_UNESCAPED_UNICODE) . PHP_EOL;
} finally {
    if ($restoreType) {
        $restore = $store->prepare('UPDATE ' . $s('user')
            . ' SET TYPE=? WHERE ID=? AND UUID=? AND ACCOUNT=?');
        $restore->execute([$originalType, (int)$order['user_id'],
            (string)$linked['uuid'], $marker]);
        $check = $read($store, 'SELECT TYPE FROM ' . $s('user')
            . ' WHERE ID=?', [(int)$order['user_id']]);
        if ((int)($check['type'] ?? -1) !== $originalType) {
            throw new RuntimeException('Synthetic refund admin permission not restored');
        }
    }
}
