<?php
declare(strict_types=1);

$lane = (string)($argv[1] ?? '');
if (!in_array($lane, ['B', 'C'], true)) {
    fwrite(STDERR, "DENIED business_http=0 business_dml=0\n"); exit(78);
}
if ($lane === 'B') {
    $config = include '/tmp/zhct-http-store-mysql.dQTTBP/application/config/local/database.php';
    if (!is_array($config) || ($config['database'] ?? '') !== 'zhct'
        || hash('sha256', (string)($config['hostname'] ?? ''))
            !== '47e8be48b0cfd56dcdb9d9d426e6637b245f340b4efad4cd2f084ec5851ecc8e') {
        throw new RuntimeException('B code-local Store MySQL identity drift');
    }
    $db = new PDO('mysql:host=' . $config['hostname'] . ';port=3306;dbname=zhct;charset=utf8',
        $config['username'], $config['password'],
        [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_CASE => PDO::CASE_LOWER]);
    $port = 18081;
} else {
    if (getenv('POC_DIALECT') !== 'dm' || getenv('POC_HOST') !== '127.0.0.1'
        || getenv('POC_PORT') !== '5237' || getenv('POC_SCHEMA') !== 'ZHCT_APP'
        || getenv('POC_USER') !== 'ZHCT_APP') {
        throw new RuntimeException('C isolated Store DM identity drift');
    }
    $db = new PDO('dm:host=127.0.0.1;port=5237;schema=ZHCT_APP',
        getenv('POC_USER'), getenv('POC_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() !== 'ZHCT_APP') {
        throw new RuntimeException('C schema drift');
    }
    $port = 18080;
}
$http = static function (string $path, array $form = []) use ($port): array {
    $ctx = stream_context_create(['http' => [
        'method' => 'POST', 'header' => "Content-Type: application/x-www-form-urlencoded\r\n",
        'content' => http_build_query($form, '', '&', PHP_QUERY_RFC3986),
        'ignore_errors' => true, 'timeout' => 20, 'follow_location' => 0,
    ]]);
    $handle = @fopen('http://127.0.0.1:' . $port . $path, 'rb', false, $ctx);
    if (!is_resource($handle)) throw new RuntimeException('isolated Store HTTP unavailable');
    $raw = stream_get_contents($handle, 4194305);
    fclose($handle);
    if (!is_string($raw) || strlen($raw) > 4194304) throw new RuntimeException('HTTP response cap');
    $body = json_decode($raw, true);
    if (!is_array($body) || (int)($body['code'] ?? -1) !== 0) {
        throw new RuntimeException('business response failed at ' . $path
            . ' code=' . (string)($body['code'] ?? 'nonjson')
            . ' message=' . substr((string)($body['message'] ?? ''), 0, 160));
    }
    return $body;
};
$source = static function (string $sql) use ($db): array {
    return array_map(static function (array $row): array {
        return array_change_key_case($row, CASE_LOWER);
    }, $db->query($sql)->fetchAll(PDO::FETCH_ASSOC));
};
$dishes = $source('SELECT d.id,d.uuid,d.name,d.category,d.status,d.is_del,d.weight,d.price FROM ydy_dishes d'
    . ' WHERE d.category=1 AND d.status=1 AND d.is_del=1 AND d.weight>0'
    . ' AND EXISTS (SELECT 1 FROM ydy_dish c WHERE c.dishes_uuid=d.uuid)'
    . ' ORDER BY id ASC' . ($lane === 'B' ? ' LIMIT 100' : ' FETCH FIRST 100 ROWS ONLY'));
if (!$dishes) throw new RuntimeException('source dish absent');
$dish = $dishes[0];
$component = $db->prepare('SELECT uuid,dishes_uuid,composition_name FROM ydy_dish'
    . ' WHERE dishes_uuid=? ORDER BY id ASC'
    . ($lane === 'B' ? ' LIMIT 1' : ' FETCH FIRST 1 ROWS ONLY'));
$component->execute([(string)$dish['uuid']]);
$componentRow = $component->fetch(PDO::FETCH_ASSOC);
if (!is_array($componentRow)) throw new RuntimeException('chosen dish composition absent');
$componentRow = array_change_key_case($componentRow, CASE_LOWER);
$dishLookup = $db->prepare('SELECT COUNT(*) FROM ydy_dishes WHERE uuid=? AND name=?');
$dishLookup->execute([(string)$dish['uuid'], (string)$dish['name']]);
if ((int)$dishLookup->fetchColumn() !== 1) throw new RuntimeException('chosen dish not unique');
$stationRows = $source('SELECT uuid,name FROM ydy_station WHERE status=1 ORDER BY id DESC');
if (!$stationRows) throw new RuntimeException('station source empty');
$cater = $http('/p/api/CaterList', ['page' => 1, 'page_size' => 10])['data'] ?? null;
if (!is_array($cater) || !is_array($cater['rows'] ?? null)
    || !is_array($cater['category'] ?? null) || count($cater['category']) !== 7
    || count($cater['rows']) !== 10) {
    throw new RuntimeException('CaterList response shape or positive page invalid');
}
$countDish = static function (string $filter) use ($db): int {
    return (int)$db->query('SELECT COUNT(*) FROM ydy_dishes WHERE is_del=1 AND status=1'
        . $filter)->fetchColumn();
};
foreach ($cater['category'] as $index => $group) {
    $expected = $index === 0 ? $countDish(' AND category<>7')
        : $countDish(' AND category=' . $index);
    if ((int)($group['catergory'] ?? -1) !== $index
        || (int)($group['count'] ?? -1) !== $expected) {
        throw new RuntimeException('CaterList category count differs from original dishes');
    }
}
$rowLookup = $db->prepare('SELECT name FROM ydy_dishes WHERE uuid=? AND status=1 AND is_del=1');
foreach ($cater['rows'] as $row) {
    $rowLookup->execute([(string)($row['uuid'] ?? '')]);
    if ((string)$rowLookup->fetchColumn() !== (string)($row['name'] ?? '')) {
        throw new RuntimeException('CaterList row differs from original dish');
    }
}
$detail = $http('/p/api/find', ['uuid' => $dish['uuid']])['data'] ?? null;
if (!is_array($detail) || (string)($detail['uuid'] ?? '') !== (string)$dish['uuid']
    || (string)($detail['name'] ?? '') !== (string)$dish['name']) {
    throw new RuntimeException('dish detail differs from original row');
}
$dishFull = $db->prepare('SELECT * FROM ydy_dishes WHERE uuid=?');
$dishFull->execute([(string)$dish['uuid']]);
$originalDish = $dishFull->fetch(PDO::FETCH_ASSOC);
if (!is_array($originalDish)) throw new RuntimeException('original dish absent after HTTP');
$originalDish = array_change_key_case($originalDish, CASE_LOWER);
$decimalFields = [
    'weight', 'raw_flag_weight', 'energy', 'carbohydrate', 'protein', 'fat',
    'sfa', 'mufa', 'pufa', 'cholesterol', 'va', 'renieratene', 'retinol',
    'vb1', 'vb2', 'vpp', 'vc', 've', 'folic_acid', 'biotin',
    'pantothenic_acid', 'choline', 'potassium', 'sodium', 'calcium',
    'magnesium', 'iron', 'zinc', 'selenium', 'gi', 'gl', 'purine',
    'dietary_fiber', 'moisture', 'ash', 'iodine', 'phosphorus',
    'cuprum', 'manganese',
];
foreach ($decimalFields as $field) {
    if (!array_key_exists($field, $detail)
        || $detail[$field] !== bcadd((string)$originalDish[$field], '0', 2)) {
        throw new RuntimeException('dish DECIMAL response differs from original row');
    }
}
if (!is_numeric($detail['price'] ?? null)
    || abs((float)$detail['price'] - (float)$originalDish['price']) > 0.00001) {
    throw new RuntimeException('dish FLOAT price differs from original row');
}
$byUuids = $http('/p/api/get_dish_uuids', ['uuids' => $componentRow['uuid']])['data'] ?? null;
if (!is_array($byUuids) || count($byUuids) !== 1
    || (string)($byUuids[0]['uuid'] ?? '') !== (string)$componentRow['uuid']
    || (string)($byUuids[0]['dishes_uuid'] ?? '') !== (string)$componentRow['dishes_uuid']
    || (string)($byUuids[0]['composition_name'] ?? '') !== (string)$componentRow['composition_name']) {
    throw new RuntimeException('dish batch UUID lookup differs from original row shape='
        . (is_array($byUuids) ? json_encode(array_keys($byUuids)) : gettype($byUuids)));
}
$stations = $http('/p/api/station_list')['data'] ?? null;
if (!is_array($stations) || count($stations) !== count($stationRows)) {
    throw new RuntimeException('station list count differs from original table');
}
foreach ($stations as $index => $row) {
    if ((string)($row['uuid'] ?? '') !== (string)$stationRows[$index]['uuid']
        || (string)($row['name'] ?? '') !== (string)$stationRows[$index]['name']) {
        throw new RuntimeException('station list row/order differs from original table');
    }
}
if ($stationRows !== $source('SELECT uuid,name FROM ydy_station WHERE status=1 ORDER BY id DESC')) {
    throw new RuntimeException('station source changed during read');
}
$dishLookup->execute([(string)$dish['uuid'], (string)$dish['name']]);
if ((int)$dishLookup->fetchColumn() !== 1) throw new RuntimeException('chosen dish changed during read');
$typeMap = static function (array $row): array {
    $map = [];
    foreach ($row as $field => $value) $map[$field] = gettype($value);
    ksort($map);
    return $map;
};
$caterTypes = $typeMap($cater['rows'][0]);
$findTypes = $typeMap($detail);
$jsonTypes = array_map(static function (string $type): string {
    return in_array($type, ['integer', 'double'], true) ? 'number' : $type;
}, $findTypes);
echo json_encode(['lane' => $lane, 'http_business_ok' => 4,
    'cater_first_page' => count($cater['rows']),
    'cater_all_count' => (int)$cater['category'][0]['count'],
    'find_source_uuid_name_equal' => true,
    'find_all_decimal_fields_source_equal' => count($decimalFields),
    'component_uuid_batch_one_source_equal' => true,
    'stations_source_equal_count' => count($stations),
    'cater_row_type_sha256' => hash('sha256', json_encode($caterTypes)),
    'find_type_sha256' => hash('sha256', json_encode($findTypes)),
    'find_json_type_sha256' => hash('sha256', json_encode($jsonTypes)),
    'business_dml' => 0], JSON_UNESCAPED_SLASHES), PHP_EOL;
