<?php
declare(strict_types=1);

// A/B-only, user-approved ai_api/.env.local Store development MySQL, read-only.
set_exception_handler(static function (Throwable $error): void {
    echo json_encode(['status' => 'restaurant-chain-ab-error',
        'class' => get_class($error), 'code' => (string)$error->getCode()],
        JSON_UNESCAPED_SLASHES), PHP_EOL;
    exit(2);
});
$target = (string)getenv('POC_AB_TARGET');
$base = $target === 'A' ? 'http://127.0.0.1:18105'
    : ($target === 'B' ? 'http://127.0.0.1:18101' : '');
$configPath = realpath((string)getenv('POC_MYSQL_LOCAL_ENV'));
$expectedPath = '/Users/wiscourper/Documents/workspace/zhct/zhctproject/ai_api/.env.local';
if ($base === '' || $configPath !== $expectedPath || !is_file($configPath)) {
    throw new RuntimeException('A/B local development boundary unavailable');
}
$config = parse_ini_file($configPath, true, INI_SCANNER_RAW);
$store = is_array($config) ? ($config['DATABASE_ZHCT'] ?? []) : [];
foreach (['HOSTNAME', 'HOSTPORT', 'DATABASE', 'USERNAME', 'PASSWORD'] as $key) {
    if (!isset($store[$key]) || (string)$store[$key] === '') {
        throw new RuntimeException('Local Store development connection incomplete');
    }
}
$charset = strtolower((string)($store['CHARSET'] ?? 'utf8'));
if (!in_array($charset, ['utf8', 'utf8mb4'], true)) {
    throw new RuntimeException('Unexpected local MySQL charset');
}
$boundary = json_decode((string)file_get_contents($base . '/__poc_boundary'), true);
if (!is_array($boundary) || empty($boundary['external_stubs'])) {
    throw new RuntimeException('A/B external-stub boundary unavailable');
}
$pdo = new PDO('mysql:host=' . $store['HOSTNAME'] . ';port=' . $store['HOSTPORT']
    . ';dbname=' . $store['DATABASE'] . ';charset=' . $charset,
    $store['USERNAME'], $store['PASSWORD'], [
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_CASE => PDO::CASE_LOWER,
        PDO::ATTR_STRINGIFY_FETCHES => false,
        PDO::ATTR_EMULATE_PREPARES => false,
    ]);
$schema = (string)$pdo->query('SELECT DATABASE()')->fetchColumn();
if ($schema !== (string)$store['DATABASE']) {
    throw new RuntimeException('Local Store database mismatch');
}
$candidateSql = 'SELECT a.id AS area_id,s.id AS shop_id,r.id AS restaurant_id '
    . 'FROM ydy_restaurant_area a '
    . 'JOIN ydy_restaurant_shop s ON s.area_id=a.id '
    . 'JOIN ydy_restaurants r ON r.restaurant_shop_id=s.id '
    . 'WHERE a.is_delete=0 AND a.status=1 '
    . 'AND s.is_delete=0 AND s.status=1 '
    . 'AND r.is_delete=2 AND r.status=1 AND r.stall_type IN (2,3) '
    . 'ORDER BY a.id,s.id,r.id';
$candidate = $pdo->query($candidateSql)->fetch(PDO::FETCH_ASSOC);
if (!is_array($candidate)) throw new RuntimeException('No active related restaurant chain');
$areaId = (int)$candidate['area_id'];
$shopId = (int)$candidate['shop_id'];
$restaurantId = (int)$candidate['restaurant_id'];
$countStmt = $pdo->prepare(
    'SELECT COUNT(*) FROM ydy_restaurants WHERE restaurant_shop_id=? '
    . 'AND is_delete=2 AND status=1 AND stall_type IN (2,3)');
$countStmt->execute([$shopId]);
$stallCount = (int)$countStmt->fetchColumn();
if ($areaId < 1 || $shopId < 1 || $restaurantId < 1 || $stallCount < 1) {
    throw new RuntimeException('Local related restaurant chain invalid');
}
$shape = null;
$shape = static function ($value, int $depth = 0) use (&$shape) {
    if (!is_array($value)) return gettype($value);
    if ($depth >= 3) return ['array_count' => count($value)];
    if ($value === []) return ['list_count' => 0];
    if (array_keys($value) === range(0, count($value) - 1)) {
        return ['list_count' => count($value), 'first' => $shape($value[0], $depth + 1)];
    }
    $types = [];
    foreach ($value as $key => $item) $types[$key] = $shape($item, $depth + 1);
    return $types;
};
$request = static function (string $method, string $path, array $params) use ($base): array {
    $query = ['storeId' => 10001];
    if ($method === 'GET') $query += $params;
    $url = $base . $path . '?' . http_build_query($query);
    $options = ['method' => $method, 'ignore_errors' => true,
        'timeout' => 35, 'header' => "platform: POC\r\n"];
    if ($method === 'POST') {
        $options['header'] .= "Content-Type: application/x-www-form-urlencoded\r\n";
        $options['content'] = http_build_query($params);
    }
    $started = microtime(true);
    $bodyText = file_get_contents($url, false, stream_context_create(['http' => $options]));
    $line = $http_response_header[0] ?? '';
    $code = preg_match('/HTTP\/\S+\s+(\d+)/', $line, $match) ? (int)$match[1] : 0;
    return ['http' => $code,
        'elapsed_ms' => (int)round((microtime(true) - $started) * 1000),
        'body' => is_string($bodyText) ? json_decode($bodyText, true) : null];
};
$findId = static function ($items, int $id): ?array {
    if (!is_array($items)) return null;
    foreach ($items as $item) {
        if (is_array($item) && (int)($item['id'] ?? 0) === $id) return $item;
    }
    return null;
};
$cases = [
    'areaList' => ['POST', '/api/restaurant/areaList', []],
    'shopList' => ['POST', '/api/restaurant/shopList', ['area_id' => $areaId]],
    'list' => ['POST', '/api/restaurant/list', ['shop_id' => $shopId]],
    'detail' => ['GET', '/api/restaurant/detail', ['restaurant_id' => $restaurantId]],
];
$evidence = [];
$haltSensitive = false;
foreach ($cases as $name => [$method, $path, $params]) {
    try {
        $response = $request($method, $path, $params);
        $body = $response['body'];
        $data = is_array($body) ? ($body['data'] ?? null) : null;
        $list = is_array($data) ? ($data['list'] ?? null) : null;
        $selected = null;
        $relation = false;
        if ($name === 'areaList') {
            $selected = $findId($list, $areaId);
            $relation = $selected !== null && is_array($list) && count($list) > 0;
        } elseif ($name === 'shopList') {
            $selected = $findId($list, $shopId);
            $relation = $selected !== null
                && (int)($selected['stall_count'] ?? -1) === $stallCount;
        } elseif ($name === 'list') {
            $selected = $findId($list, $restaurantId);
            $relation = $selected !== null
                && (int)($data['stall_count'] ?? -1) === count($list);
        } else {
            $selected = is_array($data) ? ($data['detail'] ?? null) : null;
            $relation = is_array($selected)
                && (int)($selected['id'] ?? 0) === $restaurantId;
        }
        $secretKeys = ['zpkey', 'zpchargekey', 'zpchargeapiurl',
            'zpbzapiurl', 'zpapiurl', 'zpterm', 'zpchargeterm'];
        $secretLeak = false;
        $feeTypesMatch = true;
        if ($name === 'list' && is_array($list)) {
            foreach ($list as $item) {
                if (!is_array($item)) {
                    $feeTypesMatch = false;
                    continue;
                }
                $secretLeak = $secretLeak
                    || count(array_intersect($secretKeys,
                        array_map('strtolower', array_keys($item)))) > 0;
                $feeTypesMatch = $feeTypesMatch
                    && is_string($item['package_fee'] ?? null)
                    && is_string($item['locker_package_fee'] ?? null);
            }
        }
        $ok = $response['http'] === 200
            && is_array($body) && (int)($body['status'] ?? -1) === 200
            && $relation && !$secretLeak && $feeTypesMatch;
        $evidence[$name] = [
            'method' => $method, 'path' => $path,
            'http' => $response['http'],
            'business_status' => is_array($body) ? ($body['status'] ?? null) : null,
            'message_sha256' => is_array($body)
                ? hash('sha256', (string)($body['message'] ?? '')) : null,
            'elapsed_ms' => $response['elapsed_ms'],
            'data_shape' => $shape($data),
            'selected_id_type' => is_array($selected)
                ? gettype($selected['id'] ?? null) : null,
            'sensitive_key_leak' => $secretLeak,
            'fee_fields_are_strings' => $name === 'list' ? $feeTypesMatch : null,
            'relation_matches_original_tables' => $relation,
            'pass' => $ok,
        ];
        if ($secretLeak) {
            $haltSensitive = true;
            break;
        }
    } catch (Throwable $failure) {
        $evidence[$name] = ['method' => $method, 'path' => $path,
            'error_class' => get_class($failure),
            'error_code' => (string)$failure->getCode(), 'pass' => false];
    }
}
$countStmt->execute([$shopId]);
$afterCount = (int)$countStmt->fetchColumn();
$pass = $afterCount === $stallCount;
foreach ($evidence as $case) $pass = $pass && ($case['pass'] ?? false);
echo json_encode(['status' => $haltSensitive ? 'sensitive-key-red'
        : ($pass ? 'restaurant-chain-ab-pass' : 'restaurant-chain-ab-fail'),
    'target' => $target, 'source' => 'local-development-mysql',
    'area_id' => $areaId, 'shop_id' => $shopId,
    'restaurant_id' => $restaurantId,
    'original_shop_stall_count' => $stallCount,
    'after_shop_stall_count' => $afterCount,
    'cases' => $evidence],
    JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), PHP_EOL;
exit($pass ? 0 : 3);
