<?php
declare(strict_types=1);

// One read-only mobile request in the isolated A or B service; no test-data DML.
set_exception_handler(static function (Throwable $error): void {
    echo json_encode(['status' => 'order-list-ab-error', 'class' => get_class($error),
        'code' => (string)$error->getCode()], JSON_UNESCAPED_SLASHES), PHP_EOL;
    exit(2);
});
$target = (string)getenv('POC_AB_TARGET');
$targets = [
    'A' => [13109, '18105', '/tmp/zhct-http-ai-macos.zjaU8h',
        '11ef8be01a99a64efb64fceadd2b73b4d855c4f62ebada814245ab079d458f6e'],
    'B' => [13127, '18101', '/tmp/zhct-http-ai-macos.x2CCZX',
        '7d91cc13b226732a3f53293b97a18384136826a3aab27e7dc8715e29cf28d9fc'],
];
if (!isset($targets[$target])) throw new RuntimeException('Unknown A/B lane');
[$pid, $port, $root, $sourceSha] = $targets[$target];
$selfSha = (string)getenv('CDX_READ_SCRIPT_SHA');
if (getenv('CDX_READ_APPROVED') !== 'ORDER_LIST_READ_V1'
    || $selfSha === '' || hash_file('sha256', __FILE__) !== $selfSha) {
    throw new RuntimeException('Read execution gate missing');
}
$ps = (string)shell_exec('ps -p ' . $pid . ' -o command=');
if (strpos($ps, '127.0.0.1:' . $port) === false
    || strpos($ps, $root . '/public') === false) {
    throw new RuntimeException('Isolated process changed');
}
if (hash_file('sha256', $root . '/app/api/model/Restaurant.php') !== $sourceSha) {
    throw new RuntimeException('A/B source drift');
}
$base = 'http://127.0.0.1:' . $port;
$boundary = json_decode((string)file_get_contents($base . '/__poc_boundary'), true);
if (!is_array($boundary) || ($boundary['external_stubs'] ?? false) !== true) {
    throw new RuntimeException('External stub boundary missing');
}
$configPath = realpath((string)getenv('POC_MYSQL_LOCAL_ENV'));
if ($configPath !== '/Users/wiscourper/Documents/workspace/zhct/zhctproject/ai_api/.env.local') {
    throw new RuntimeException('Wrong local MySQL config');
}
$config = parse_ini_file($configPath, true, INI_SCANNER_RAW);
$store = $config['DATABASE_ZHCT'] ?? [];
foreach (['HOSTNAME', 'HOSTPORT', 'DATABASE', 'USERNAME', 'PASSWORD'] as $key) {
    if (empty($store[$key])) throw new RuntimeException('Missing dev DB setting');
}
$pdo = new PDO('mysql:host=' . $store['HOSTNAME'] . ';port=' . $store['HOSTPORT']
    . ';dbname=' . $store['DATABASE'] . ';charset=' . ($store['CHARSET'] ?? 'utf8'),
    $store['USERNAME'], $store['PASSWORD'], [
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_CASE => PDO::CASE_LOWER,
        PDO::ATTR_EMULATE_PREPARES => false,
    ]);
$identity = (string)$pdo->query(
    "SELECT CONCAT(@@server_uuid,'|',@@hostname,'|',@@port,'|',DATABASE())"
)->fetchColumn();
if (hash('sha256', $identity) !==
    '003eb5aecf1cd4595b609c1f7f20b9ee325b578309fb9fe14fedaf77584fa401') {
    throw new RuntimeException('Not the approved local dev Store MySQL');
}
$today = date('Y-m-d');
$until = date('Y-m-d', strtotime('+30 days'));
$candidate = $pdo->prepare('SELECT r.restaurant_id,r.menu_date,r.meal_times '
    . 'FROM ydy_recipes r JOIN ydy_dishes d ON d.uuid=r.dishes_uuid '
    . 'JOIN ydy_restaurants s ON s.id=r.restaurant_id '
    . 'WHERE r.menu_date BETWEEN ? AND ? AND d.is_delete=0 AND d.ai_dishes_id>0 '
    . 'AND s.is_delete=2 AND s.status=1 AND s.stall_type IN (1,2,3) '
    . 'ORDER BY r.menu_date,r.restaurant_id LIMIT 1');
$candidate->execute([$today, $until]);
$row = $candidate->fetch(PDO::FETCH_ASSOC);
if (!is_array($row)) throw new RuntimeException('No natural future recipe');
$restaurantId = (int)$row['restaurant_id'];
$menuDate = substr((string)$row['menu_date'], 0, 10);
$mealTimes = (int)$row['meal_times'];
$restaurant = $pdo->prepare('SELECT * FROM ydy_restaurants WHERE id=?');
$recipes = $pdo->prepare('SELECT r.*,d.id AS dish_id,d.ai_dishes_id,d.is_delete AS dish_deleted '
    . 'FROM ydy_recipes r JOIN ydy_dishes d ON d.uuid=r.dishes_uuid '
    . 'WHERE r.restaurant_id=? AND r.menu_date=? AND r.meal_times=? ORDER BY r.id');
$snapshot = static function () use ($restaurant, $recipes, $restaurantId, $menuDate, $mealTimes): array {
    $restaurant->execute([$restaurantId]);
    $restaurantRow = $restaurant->fetch(PDO::FETCH_ASSOC);
    $recipes->execute([$restaurantId, $menuDate, $mealTimes]);
    $recipeRows = $recipes->fetchAll(PDO::FETCH_ASSOC);
    $activeCount = 0;
    foreach ($recipeRows as $recipe) {
        if ((int)$recipe['dish_deleted'] === 0 && (int)$recipe['ai_dishes_id'] > 0) ++$activeCount;
    }
    return ['restaurant' => hash('sha256', json_encode($restaurantRow)),
        'recipe_dishes' => hash('sha256', json_encode($recipeRows)),
        'active_dish_count' => $activeCount];
};
$before = $snapshot();
if ($before['active_dish_count'] < 1) throw new RuntimeException('Selected recipe has no active dish');
$restaurant->execute([$restaurantId]);
$businessRow = $restaurant->fetch(PDO::FETCH_ASSOC);
$bookRules = json_decode((string)($businessRow['book_rules'] ?? ''), true);
$stallType = (int)($businessRow['stall_type'] ?? 0);
$bookRuleType = is_array($bookRules) ? ($bookRules['rule'] ?? null) : null;
$url = $base . '/api/restaurant/orderList?storeId=10001';
$request = stream_context_create(['http' => ['method' => 'POST', 'ignore_errors' => true,
    'timeout' => 30,
    'header' => "platform: POC\r\nContent-Type: application/x-www-form-urlencoded\r\n",
    'content' => http_build_query(['restaurant_id' => $restaurantId])]]);
$started = microtime(true);
$raw = file_get_contents($url, false, $request);
$elapsedMs = (int)round((microtime(true) - $started) * 1000);
$line = $http_response_header[0] ?? '';
$http = preg_match('/HTTP\/\S+\s+(\d+)/', $line, $match) ? (int)$match[1] : 0;
$body = is_string($raw) && strlen($raw) <= 1000000 ? json_decode($raw, true) : null;
$dates = is_array($body) ? ($body['data']['list'] ?? null) : null;
$matched = null;
if (is_array($dates)) {
    foreach ($dates as $date) {
        if (!is_array($date) || substr((string)($date['date'] ?? ''), 0, 10) !== $menuDate) continue;
        foreach (($date['meal'] ?? []) as $meal) {
            if (is_array($meal) && (int)($meal['value'] ?? 0) === $mealTimes) {
                $matched = ['date' => (string)$date['date'],
                    'weekday_type' => gettype($date['weekday'] ?? null),
                    'meal_value_type' => gettype($meal['value'] ?? null),
                    'dishes_num_type' => gettype($meal['dishes_num'] ?? null),
                    'dishes_num' => (int)($meal['dishes_num'] ?? -1),
                    'meal_keys' => array_keys($meal)];
            }
        }
    }
}
$after = $snapshot();
$normalized = is_array($body) ? $body : null;
if (is_array($normalized)) unset($normalized['trace_id']);
$pass = $http === 200 && is_array($body) && (int)($body['status'] ?? 0) === 200
    && is_array($dates) && count($dates) > 0 && is_array($matched)
    && $matched['dishes_num'] === $before['active_dish_count']
    && $before === $after;
echo json_encode(['status' => $pass ? 'order-list-ab-pass' : 'order-list-ab-fail',
    'lane' => $target, 'http' => $http, 'business_status' => $body['status'] ?? null,
    'elapsed_ms' => $elapsedMs, 'restaurant_id' => $restaurantId,
    'source_stall_type' => $stallType, 'source_book_rule_type' => $bookRuleType,
    'menu_date' => $menuDate, 'meal_times' => $mealTimes,
    'source_active_dishes' => $before['active_dish_count'],
    'response_dates' => is_array($dates) ? count($dates) : null,
    'selected' => $matched, 'original_table_hashes_unchanged' => $before === $after,
    'response_contract_sha256' => is_array($normalized)
        ? hash('sha256', json_encode($normalized, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)) : null,
    'db_fingerprint' => hash('sha256', $identity),
    'source_sha256' => $sourceSha], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), PHP_EOL;
exit($pass ? 0 : 3);
