<?php
declare(strict_types=1);

$phase = (string)($argv[1] ?? '');
$lane = (string)($argv[2] ?? '');
$marker = (string)($argv[3] ?? '');
if (!in_array($phase, ['--audit', '--run'], true)
    || !in_array($lane, ['B', 'C'], true)
    || !preg_match('/^CDXO[A-F0-9]{16}$/D', $marker)
    || ($phase === '--run' && getenv('CDX_ORDER_READ_RUN') !== 'ONE_UNPAID_ORDER_GOOD_V1')) {
    fwrite(STDERR, "DENIED business_http=0 business_dml=0\n");
    exit(78);
}
$root = $lane === 'B' ? '/private/tmp/zhct-http-ai-macos.x2CCZX'
    : '/tmp/zhct-ai-http-20260929.3XDj3w';
$port = $lane === 'B' ? 18101 : 18102;
if (!is_file($root . '/public/index.php') || !is_file($root . '/vendor/autoload.php')) {
    throw new RuntimeException('isolated AI worker root absent');
}
if ($lane === 'B') {
    $ini = parse_ini_file('/Users/wiscourper/Documents/workspace/zhct/zhctproject/ai_api/.env.local', true, INI_SCANNER_RAW);
    $aiCfg = is_array($ini) ? ($ini['DATABASE'] ?? null) : null;
    $storeCfg = is_array($ini) ? ($ini['DATABASE_ZHCT'] ?? null) : null;
    if (!is_array($aiCfg) || !is_array($storeCfg)
        || strtolower((string)($aiCfg['TYPE'] ?? '')) !== 'mysql'
        || (string)($aiCfg['HOSTPORT'] ?? '') !== '3306'
        || hash('sha256', (string)($aiCfg['HOSTNAME'] ?? '')) !== '47e8be48b0cfd56dcdb9d9d426e6637b245f340b4efad4cd2f084ec5851ecc8e'
        || hash('sha256', (string)($aiCfg['DATABASE'] ?? '')) !== 'cf7756b3bb52cf72f625689134015b877fdab3ad8eb3bb2ddd962bb35f6efd66') {
        throw new RuntimeException('B code-local AI identity drift');
    }
    foreach (['POC_DIALECT' => 'mysql',
        'POC_AI_HOST' => $aiCfg['HOSTNAME'], 'POC_AI_PORT' => $aiCfg['HOSTPORT'],
        'POC_AI_SCHEMA' => $aiCfg['DATABASE'], 'POC_AI_USER' => $aiCfg['USERNAME'],
        'POC_AI_PASSWORD' => $aiCfg['PASSWORD'],
        'POC_HOST' => $storeCfg['HOSTNAME'], 'POC_PORT' => $storeCfg['HOSTPORT'],
        'POC_SCHEMA' => $storeCfg['DATABASE'], 'POC_USER' => $storeCfg['USERNAME'],
        'POC_PASSWORD' => $storeCfg['PASSWORD']] as $name => $value) {
        putenv($name . '=' . $value);
    }
    $db = new PDO('mysql:host=' . $aiCfg['HOSTNAME'] . ';port=3306;dbname='
        . $aiCfg['DATABASE'] . ';charset=' . $aiCfg['CHARSET'],
        $aiCfg['USERNAME'], $aiCfg['PASSWORD'],
        [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_CASE => PDO::CASE_LOWER]);
} else {
    if (getenv('POC_DIALECT') !== 'dm' || getenv('POC_AI_HOST') !== '127.0.0.1'
        || getenv('POC_AI_PORT') !== '5238' || getenv('POC_AI_SCHEMA') !== 'AIZHCT_APP'
        || getenv('POC_AI_USER') !== 'AIZHCT_APP'
        || getenv('POC_HOST') !== '127.0.0.1'
        || getenv('POC_PORT') !== '5237' || getenv('POC_SCHEMA') !== 'ZHCT_APP') {
        throw new RuntimeException('C customer database identity drift');
    }
    $db = new PDO('dm:host=127.0.0.1;port=5238;schema=AIZHCT_APP',
        getenv('POC_AI_USER'), getenv('POC_AI_PASSWORD'),
        [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_CASE => PDO::CASE_LOWER]);
    if ($db->query("SELECT SYS_CONTEXT('USERENV','CURRENT_SCHEMA') FROM DUAL")->fetchColumn() !== 'AIZHCT_APP') {
        throw new RuntimeException('C AI effective schema drift');
    }
}
$one = static function (string $sql, array $args = []) use ($db): ?array {
    $stmt = $db->prepare($sql);
    $stmt->execute($args);
    $row = $stmt->fetch(PDO::FETCH_ASSOC);
    return is_array($row) ? array_change_key_case($row, CASE_LOWER) : null;
};
$rows = static function (string $table, string $field, $value) use ($db): array {
    if (!in_array($table, ['yoshop_order', 'yoshop_order_goods'], true)
        || !in_array($field, ['order_no', 'order_id', 'goods_name'], true)) {
        throw new RuntimeException('nonallowlisted audit table or field');
    }
    $stmt = $db->prepare("SELECT * FROM {$table} WHERE {$field}=?");
    $stmt->execute([$value]);
    return array_map(static function (array $row): array {
        return array_change_key_case($row, CASE_LOWER);
    }, $stmt->fetchAll(PDO::FETCH_ASSOC));
};
$actorName = $lane === 'C' ? 'CDXPARMOB9411C2CB' : 'CDXPARMOB426CA4B0';
$actor = $one('SELECT user_id,nick_name FROM yoshop_user'
    . ' WHERE nick_name=? AND store_id=10001 AND is_delete=0', [$actorName]);
if ($actor === null || (int)$actor['user_id'] <= 0) {
    throw new RuntimeException('synthetic AI actor not uniquely available');
}
$userId = (int)$actor['user_id'];
$token = 'CDXORDTK' . strtoupper(hash('sha256', $marker));
define('TP_ENV', 'poc');
define('BUSINESS', 'aizhct');
define('ENTERPRISE_NO', '10001');
require_once $root . '/vendor/autoload.php';
(new \think\App($root))->setEnvName('poc')->initialize();
if (strtolower((string)\think\facade\Config::get('cache.default')) !== 'file'
    || realpath((string)\think\facade\Config::get('cache.stores.file.path'))
        !== realpath($root . '/runtime/cache')) {
    throw new RuntimeException('isolated File cache configuration drift');
}
$mapped = \think\facade\Db::connect('mysql_zhct')->name('user')
    ->where(['ai_user_id' => $userId, 'is_delete' => 0])->find();
if (empty($mapped) || !isset($mapped['password_version'])) {
    throw new RuntimeException('synthetic Store actor mapping/version absent');
}
$version = (int)$mapped['password_version'];
$ormUser = \app\api\model\User::detail($userId);
if (empty($ormUser) || (int)$ormUser['user_id'] !== $userId) {
    throw new RuntimeException('isolated ORM AI actor drift');
}
$owned = $rows('yoshop_order', 'order_no', $marker);
if ($phase === '--audit') {
    $goods = $rows('yoshop_order_goods', 'goods_name', $marker);
    $hasToken = \think\facade\Cache::has($token);
    echo json_encode(['lane' => $lane, 'phase' => 'audit', 'marker' => $marker,
        'owned_order_count' => count($owned), 'owned_goods_count' => count($goods),
        'owned_file_token_exists' => $hasToken,
        'business_http' => 0, 'business_dml' => 0]), PHP_EOL;
    exit(!$owned && !$hasToken ? 0 : 2);
}
if ($owned || \think\facade\Cache::has($token)) {
    throw new RuntimeException('owned order or short token already exists');
}
$http = static function (string $path, array $params = []) use ($port, $token): array {
    if (!in_array($path, ['/api/Order/list', '/api/Order/detail', '/api/Order/todoCounts'], true)) {
        throw new RuntimeException('unsupported fixed read path');
    }
    $query = http_build_query(['storeId' => 10001] + $params);
    $ctx = stream_context_create(['http' => [
        'method' => 'GET', 'header' => 'Access-Token: ' . $token . "\r\n"
            . "platform: MP-WEIXIN\r\nversion: 2.0.51\r\nenv-version: develop\r\n",
        'ignore_errors' => true, 'timeout' => 20, 'follow_location' => 0,
    ]]);
    $handle = @fopen('http://127.0.0.1:' . $port . $path . '?' . $query,
        'rb', false, $ctx);
    if (!is_resource($handle)) throw new RuntimeException('isolated AI HTTP unavailable');
    $raw = stream_get_contents($handle, 524289);
    fclose($handle);
    if (!is_string($raw) || strlen($raw) > 524288) throw new RuntimeException('AI response cap');
    $body = json_decode($raw, true);
    if (!is_array($body) || (int)($body['status'] ?? 0) !== 200) {
        throw new RuntimeException('AI business status failed at ' . $path
            . ' status=' . (string)($body['status'] ?? 'nonjson')
            . ' error=' . substr((string)($body['message'] ?? ''), 0, 100));
    }
    return $body;
};
$typeTree = static function ($value) use (&$typeTree) {
    if (!is_array($value)) return gettype($value);
    $out = [];
    foreach ($value as $key => $item) $out[$key] = $typeTree($item);
    ksort($out);
    return $out;
};
$naturalBefore = (int)$db->query('SELECT COUNT(*) FROM yoshop_order WHERE store_id=10001')->fetchColumn();
$error = null;
$result = [];
try {
    if (!\think\facade\Cache::set($token, ['user' => $ormUser, 'store_id' => 10001,
        'is_login' => true, 'password_version' => $version, 'login_type' => 'sms'], 300)
        || !\think\facade\Cache::has($token)) {
        throw new RuntimeException('short isolated File token unavailable');
    }
    $pre = $http('/api/Order/todoCounts');
    $prePayment = (int)($pre['data']['counts']['payment'] ?? -1);
    if ($prePayment < 0) throw new RuntimeException('preexisting payment count unavailable');
    $now = time();
    $stmt = $db->prepare('INSERT INTO yoshop_order'
        . ' (order_no,total_price,order_price,pay_price,user_id,store_id,create_time,update_time,'
        . 'pay_status,order_status,delivery_status,receipt_status,is_delete,order_source,order_source_data)'
        . ' VALUES (?,12.34,12.34,12.34,?,10001,?,?,10,10,10,10,0,10,?)');
    $stmt->execute([$marker, $userId, $now, $now, '[]']);
    $order = $rows('yoshop_order', 'order_no', $marker);
    if (count($order) !== 1 || (int)$order[0]['user_id'] !== $userId
        || bcadd((string)$order[0]['pay_price'], '0', 2) !== '12.34') {
        throw new RuntimeException('owned order insertion mismatch');
    }
    $orderId = (int)$order[0]['order_id'];
    $stmt = $db->prepare('INSERT INTO yoshop_order_goods'
        . ' (order_id,user_id,store_id,goods_id,goods_name,content,goods_weight,goods_price,'
        . 'total_num,total_price,total_pay_price,goods_props,create_time)'
        . ' VALUES (?,?,?,?,?,?,0.1,12.34,1,12.34,12.34,?,?)');
    $stmt->execute([$orderId, $userId, 10001, 0, $marker, '', '[]', $now]);
    $good = $rows('yoshop_order_goods', 'order_id', $orderId);
    if (count($good) !== 1 || (string)$good[0]['goods_name'] !== $marker
        || bcadd((string)$good[0]['total_price'], '0', 2) !== '12.34') {
        throw new RuntimeException('owned order good insertion mismatch');
    }
    $listBody = $http('/api/Order/list', ['dataType' => 'payment']);
    $page = $listBody['data']['list'] ?? null;
    $items = is_array($page) ? ($page['data'] ?? null) : null;
    if (!is_array($items)) throw new RuntimeException('order list page missing');
    $hits = array_values(array_filter($items, static function ($row) use ($marker): bool {
        return is_array($row) && (string)($row['order_no'] ?? '') === $marker;
    }));
    if (count($hits) !== 1 || (int)($hits[0]['order_id'] ?? 0) !== $orderId
        || (int)($hits[0]['user_id'] ?? 0) !== $userId
        || bcadd((string)($hits[0]['pay_price'] ?? ''), '0', 2) !== '12.34'
        || count($hits[0]['goods'] ?? []) !== 1
        || (string)($hits[0]['goods'][0]['goods_name'] ?? '') !== $marker
        || bcadd((string)($hits[0]['goods'][0]['total_price'] ?? ''), '0', 2) !== '12.34') {
        throw new RuntimeException('owned order/list relation mismatch');
    }
    $detailBody = $http('/api/Order/detail', ['orderId' => $orderId]);
    $detail = $detailBody['data']['order'] ?? null;
    if (!is_array($detail) || (int)($detail['order_id'] ?? 0) !== $orderId
        || (string)($detail['order_no'] ?? '') !== $marker
        || bcadd((string)($detail['pay_price'] ?? ''), '0', 2) !== '12.34'
        || count($detail['goods'] ?? []) !== 1
        || (string)($detail['goods'][0]['goods_name'] ?? '') !== $marker
        || bcadd((string)($detail['goods'][0]['total_price'] ?? ''), '0', 2) !== '12.34') {
        throw new RuntimeException('owned order/detail relation mismatch');
    }
    $countsBody = $http('/api/Order/todoCounts');
    $counts = $countsBody['data']['counts'] ?? null;
    if (!is_array($counts) || (int)($counts['payment'] ?? -1) !== $prePayment + 1) {
        throw new RuntimeException('owned order/todoCounts payment delta mismatch');
    }
    $result = [
        'http_business_ok' => 3, 'own_order_and_good_source_equal' => true,
        'payment_count_delta' => (int)$counts['payment'] - $prePayment,
        'list_order_type_tree_sha256' => hash('sha256', json_encode($typeTree($hits[0]))),
        'detail_order_type_tree_sha256' => hash('sha256', json_encode($typeTree($detail))),
        'counts_type_tree_sha256' => hash('sha256', json_encode($typeTree($counts))),
        'list_order_type_tree' => $typeTree($hits[0]),
        'detail_order_type_tree' => $typeTree($detail),
        'counts_type_tree' => $typeTree($counts),
        'list_good_count' => count($hits[0]['goods']),
        'detail_good_count' => count($detail['goods']),
        'order_money_json_types' => [
            'list_pay_price' => gettype($hits[0]['pay_price'] ?? null),
            'detail_pay_price' => gettype($detail['pay_price'] ?? null),
            'detail_good_total_price' => gettype($detail['goods'][0]['total_price'] ?? null),
        ],
    ];
} catch (Throwable $caught) {
    $error = $caught;
} finally {
    if ($db->inTransaction()) $db->rollBack();
    foreach ($rows('yoshop_order', 'order_no', $marker) as $ownRow) {
        $orderId = (int)$ownRow['order_id'];
        $stmt = $db->prepare('DELETE FROM yoshop_order_goods WHERE order_id=? AND user_id=? AND store_id=10001 AND goods_name=?');
        $stmt->execute([$orderId, $userId, $marker]);
        $stmt = $db->prepare('DELETE FROM yoshop_order WHERE order_id=? AND order_no=? AND user_id=? AND store_id=10001');
        $stmt->execute([$orderId, $marker, $userId]);
    }
    \think\facade\Cache::delete($token);
}
if ($rows('yoshop_order', 'order_no', $marker)
    || $rows('yoshop_order_goods', 'goods_name', $marker)
    || \think\facade\Cache::has($token)) {
    throw new RuntimeException('owned order/token cleanup failed');
}
$naturalAfter = (int)$db->query('SELECT COUNT(*) FROM yoshop_order WHERE store_id=10001')->fetchColumn();
if ($naturalBefore !== $naturalAfter) throw new RuntimeException('natural order count changed');
if ($error !== null) {
    fwrite(STDERR, get_class($error) . ': ' . $error->getMessage() . "\n");
    exit(1);
}
echo json_encode(['lane' => $lane, 'marker' => $marker] + $result + [
    'owned_order_good_token_cleanup_zero' => true,
    'business_dml' => 'one-own-order-and-good-insert-delete-only',
    'third_party_payment_refund_delivery' => 0,
], JSON_UNESCAPED_SLASHES), PHP_EOL;
