<?php
declare(strict_types=1);

// C non-production only: one existing Store relation, four read-only AI HTTP APIs.
set_exception_handler(static function (Throwable $error): void {
    echo json_encode(['status' => 'restaurant-chain-error',
        'class' => get_class($error), 'code' => (string)$error->getCode()],
        JSON_UNESCAPED_SLASHES), PHP_EOL;
    exit(2);
});
$raw = file_get_contents('/proc/53772/environ');
if ($raw === false) throw new RuntimeException('Approved C POC unavailable');
$env = [];
foreach (explode("\0", $raw) as $part) {
    if (strpos($part, 'POC_') !== 0) continue;
    $position = strpos($part, '=');
    if ($position !== false) $env[substr($part, 0, $position)] = substr($part, $position + 1);
}
$cmdline = file_get_contents('/proc/53772/cmdline');
if (($env['POC_DIALECT'] ?? '') !== 'dm'
    || ($env['POC_EXTERNAL_STUBS'] ?? '') !== '1'
    || ($env['POC_HOST'] ?? '') !== '127.0.0.1'
    || ($env['POC_PORT'] ?? '') !== '5237'
    || ($env['POC_SCHEMA'] ?? '') !== 'ZHCT_APP'
    || ($env['POC_AI_PORT'] ?? '') !== '5238'
    || ($env['POC_AI_SCHEMA'] ?? '') !== 'AIZHCT_APP'
    || empty($env['POC_USER']) || empty($env['POC_PASSWORD'])
    || $cmdline === false
    || strpos($cmdline, '/tmp/zhct-ai-http-20260929.3XDj3w/public') === false
    || strpos($cmdline, '127.0.0.1:18102') === false) {
    throw new RuntimeException('C isolated boundary mismatch');
}
$base = 'http://127.0.0.1:18102';
$boundary = json_decode((string)file_get_contents($base . '/__poc_boundary'), true);
if (!is_array($boundary) || empty($boundary['external_stubs'])) {
    throw new RuntimeException('C external-stub boundary unavailable');
}
$pdo = new PDO('dm:host=127.0.0.1;port=5237;schema=ZHCT_APP',
    $env['POC_USER'], $env['POC_PASSWORD'], [
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_CASE => PDO::CASE_LOWER,
    ]);
$user = strtoupper((string)$pdo->query('SELECT USER FROM DUAL')->fetchColumn());
$schema = strtoupper((string)$pdo->query(
    "SELECT SYS_CONTEXT('USERENV','CURRENT_SCHEMA') FROM DUAL"
)->fetchColumn());
if ($user !== 'ZHCT_APP' || $schema !== 'ZHCT_APP') {
    throw new RuntimeException('C Store database owner 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 nonempty 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]);
$expectedShopStallCount = (int)$countStmt->fetchColumn();
if ($areaId < 1 || $shopId < 1 || $restaurantId < 1
    || $expectedShopStallCount < 1) {
    throw new RuntimeException('Selected restaurant relation invalid');
}
$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];
    $list = array_keys($value) === range(0, count($value) - 1);
    if ($list) 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);
    }
    $context = stream_context_create(['http' => $options]);
    $started = microtime(true);
    $text = file_get_contents($url, false, $context);
    $line = $http_response_header[0] ?? '';
    $code = preg_match('/HTTP\/\S+\s+(\d+)/', $line, $matches)
        ? (int)$matches[1] : 0;
    $body = is_string($text) ? json_decode($text, true) : null;
    return ['http' => $code, 'elapsed_ms' => (int)round((microtime(true) - $started) * 1000),
        'body' => $body];
};
$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) === $expectedShopStallCount;
        } 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'];
        $secretKeyLeak = false;
        $feeTypesMatch = true;
        if ($name === 'list' && is_array($list)) {
            foreach ($list as $item) {
                if (!is_array($item)) {
                    $feeTypesMatch = false;
                    continue;
                }
                $secretKeyLeak = $secretKeyLeak
                    || 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 && !$secretKeyLeak && $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' => $secretKeyLeak,
            'fee_fields_are_strings' => $name === 'list' ? $feeTypesMatch : null,
            'relation_matches_original_tables' => $relation,
            'pass' => $ok,
        ];
        if ($secretKeyLeak) {
            $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]);
$afterShopStallCount = (int)$countStmt->fetchColumn();
$allPass = $afterShopStallCount === $expectedShopStallCount;
foreach ($evidence as $case) $allPass = $allPass && ($case['pass'] ?? false);
echo json_encode([
    'status' => $haltSensitive ? 'sensitive-key-red'
        : ($allPass ? 'restaurant-chain-c-pass' : 'restaurant-chain-c-fail'),
    'source' => 'nonproduction-dm-store-5237',
    'area_id' => $areaId, 'shop_id' => $shopId,
    'restaurant_id' => $restaurantId,
    'original_shop_stall_count' => $expectedShopStallCount,
    'after_shop_stall_count' => $afterShopStallCount,
    'cases' => $evidence,
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), PHP_EOL;
exit($allPass ? 0 : 3);
