<?php
declare(strict_types=1);

// Read-only HTTP-to-original-table checks for two Store screen endpoints.
$lane = (string)($argv[1] ?? '');
if (!in_array($lane, ['B', 'C'], true)) {
    echo "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') {
        throw new RuntimeException('B code-local Store database drift');
    }
    $db = new PDO('mysql:host=' . $config['hostname'] . ';port=3306;dbname='
        . $config['database'] . ';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 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;
}
$count = static function (string $sql) use ($db): int {
    return (int)$db->query($sql)->fetchColumn();
};
$http = static function (string $path, string $method = 'GET',
    string $form = 'restaurant_id=1') use ($port): array {
    if (!in_array($method, ['GET', 'POST'], true))
        throw new RuntimeException('unsupported screen test method');
    $options = ['method' => $method,
        'ignore_errors' => true, 'timeout' => 18, 'follow_location' => 0];
    if ($method === 'POST') {
        $options['header'] = "Content-Type: application/x-www-form-urlencoded\r\n";
        $options['content'] = $form;
    }
    $ctx = stream_context_create(['http' => $options]);
    $handle = @fopen('http://127.0.0.1:' . $port . $path, 'rb', false, $ctx);
    if (!is_resource($handle)) throw new RuntimeException('isolated screen HTTP unavailable');
    $raw = stream_get_contents($handle, 4194305); fclose($handle);
    if (!is_string($raw) || strlen($raw) > 4194304)
        throw new RuntimeException('screen response too large');
    $body = json_decode($raw, true);
    if (!is_array($body) || (int)($body['code'] ?? -1) !== 0)
        throw new RuntimeException('screen business response failed');
    return $body;
};
$namesBody = $http('/api/screen/anhuiStaffNames?restaurant_id=1&page=1&page_size=20');
$namesData = $namesBody['data'] ?? [];
$sourceNamesTotal = $count("SELECT COUNT(*) FROM ydy_staff"
    . " WHERE restaurant_id=1 AND is_show=1 AND name<>''");
$source = $db->query("SELECT name FROM ydy_staff WHERE restaurant_id=1 AND is_show=1"
    . " AND name<>'' ORDER BY CASE WHEN personnel_umber = '' THEN 1 ELSE 0 END ASC,"
    . ' personnel_umber ASC,id ASC'
    . ($lane === 'B' ? ' LIMIT 20' : ' FETCH FIRST 20 ROWS ONLY'))
    ->fetchAll(PDO::FETCH_COLUMN);
$source = array_map(static function ($name): string {
    $name = trim((string)$name);
    return preg_match('/^1\d{10}$/', $name)
        ? substr($name, 0, 3) . '****' . substr($name, -4) : $name;
}, $source);
if ((int)($namesData['total'] ?? -1) !== $sourceNamesTotal
    || ($namesData['list'] ?? null) !== $source) {
    throw new RuntimeException('staff names HTTP differs from original table');
}
$boardBody = $http('/api/screen/anhuiBoard?restaurant_id=1&date=2026-10-09');
$board = $boardBody['data'] ?? [];
$sourceStaffTotal = $count('SELECT COUNT(*) FROM ydy_staff WHERE restaurant_id=1'
    . ' AND is_show=1 AND job_status=1');
if ((int)($board['total_staff'] ?? -1) !== $sourceStaffTotal
    || count($board['days'] ?? []) !== 7
    || ($board['week_start'] ?? '') !== '2026-10-05'
    || ($board['week_end'] ?? '') !== '2026-10-11') {
    throw new RuntimeException('board staff/week differs from original table/date');
}
$rows = $db->query('SELECT r.menu_date,r.meal_times,r.dishes_uuid'
    . ' FROM ydy_recipes r LEFT JOIN ydy_dishes d ON r.dishes_uuid=d.uuid'
    . " WHERE r.restaurant_id=1 AND r.menu_date BETWEEN '2026-10-05' AND '2026-10-11'"
    . ' AND r.meal_times IN (1,2,3,4) AND d.status=1 AND d.is_del=1')
    ->fetchAll(PDO::FETCH_ASSOC);
$sourceMenu = [];
foreach ($rows as $row) {
    $row = array_change_key_case($row, CASE_LOWER);
    $key = substr((string)$row['menu_date'], 0, 10) . '|'
        . (int)$row['meal_times'] . '|' . (string)$row['dishes_uuid'];
    $sourceMenu[$key] = true;
}
$displayed = 0;
$menuTypes = [];
foreach ($board['days'] as $day) {
    foreach ($day['meals'] as $mealTimes => $items) {
        foreach ($items as $item) {
            $key = (string)$day['date'] . '|' . (int)$mealTimes
                . '|' . (string)($item['uuid'] ?? '');
            if (!isset($sourceMenu[$key]))
                throw new RuntimeException('board dish lacks original recipes/dishes row');
            $types = [];
            foreach ($item as $field => $value) $types[$field] = gettype($value);
            $menuTypes[json_encode($types)] = true;
            $displayed++;
        }
    }
}
$birthdaySource = $count('SELECT COUNT(*) FROM ydy_staff WHERE restaurant_id=1'
    . ' AND is_show=1 AND job_status=1'
    . ' AND EXTRACT(MONTH FROM birthday)=10 AND EXTRACT(DAY FROM birthday)=9');
if (count($board['birthday_people'] ?? []) !== $birthdaySource) {
    throw new RuntimeException('birthday screen count differs from original staff birthdays');
}
$surplus = $http('/api/screen/surplusBoard', 'POST')['data'] ?? [];
$equipments = $db->query('SELECT code,type FROM ydy_equipment WHERE restaurant_id=1'
    . ' AND del_flag=0 AND type IN (2,3,4,10)')->fetchAll(PDO::FETCH_ASSOC);
$expectedCodes = [];
foreach ($equipments as $equipment) {
    $equipment = array_change_key_case($equipment, CASE_LOWER);
    if ((int)$equipment['type'] === 4) {
        $expectedCodes[] = (string)$equipment['code'] . '左';
        $expectedCodes[] = (string)$equipment['code'] . '右';
    } else {
        $expectedCodes[] = (string)$equipment['code'];
    }
}
$actualCodes = array_map(static function ($row): string {
    return (string)($row['equipment_code'] ?? '');
}, $surplus['list'] ?? []);
sort($expectedCodes, SORT_STRING);
sort($actualCodes, SORT_STRING);
$surplusCount = $surplus['count'] ?? [];
if ($expectedCodes !== $actualCodes
    || count($actualCodes) !== (int)($surplusCount['normal'] ?? -1)
        + (int)($surplusCount['lack'] ?? -1)
        + (int)($surplusCount['exception'] ?? -1)) {
    throw new RuntimeException('surplus equipment list/count differs from original table');
}
$surplusTypes = [];
foreach ($surplus['list'] as $item) {
    $types = [];
    foreach ($item as $field => $value) $types[$field] = gettype($value);
    $surplusTypes[json_encode($types)] = true;
}
$operationCachedTips = $count('SELECT COUNT(*) FROM ydy_meal_suggestion'
    . " WHERE meal_date='2026-10-09' AND type=2 AND staff_id=0 AND is_delete=0");
$screenRestaurant = $lane === 'B' ? 25 : 1;
$screenForm = 'restaurant_id=' . $screenRestaurant;
$regular = $http('/m/controlScreen/everyMealSupply', 'POST', $screenForm)['data'];
$school = $http('/m/controlScreen/everyMealSupplySch', 'POST', $screenForm)['data'];
$cuisine = $http('/m/controlScreen/cuisineKind', 'POST', $screenForm)['data'];
$ingredient = $http('/m/controlScreen/offerIngredient', 'POST', $screenForm)['data'];
$mealTimes = (int)($regular['meal_times'] ?? 0);
if (!in_array($mealTimes, [1,2,3,4], true)
    || (int)($school['meal_times'] ?? 0) !== $mealTimes) {
    throw new RuntimeException('ControlScreen meal time drift');
}
$recipeQuery = $db->prepare('SELECT type,dishes_uuid FROM ydy_recipes'
    . ' WHERE restaurant_id=? AND menu_date=? AND meal_times=?');
$recipeQuery->execute([$screenRestaurant, date('Y-m-d'), $mealTimes]);
$recipeRows = $recipeQuery->fetchAll(PDO::FETCH_ASSOC);
$sourceCuisine = array_fill_keys([1,2,3,4,5,6], 0);
foreach ($recipeRows as $row) {
    $row = array_change_key_case($row, CASE_LOWER);
    $type = (int)$row['type'];
    if (isset($sourceCuisine[$type])) $sourceCuisine[$type]++;
}
foreach ($sourceCuisine as $type => $expected) {
    if ((int)($cuisine[$type][1] ?? -1) !== $expected)
        throw new RuntimeException('ControlScreen cuisine count differs from recipes');
}
$joined = $db->prepare('SELECT d.name,d.category FROM ydy_recipes r'
    . ' JOIN ydy_dishes d ON r.dishes_uuid=d.uuid'
    . ' WHERE r.restaurant_id=? AND r.menu_date=? AND r.meal_times=?');
$joined->execute([$screenRestaurant, date('Y-m-d'), $mealTimes]);
$sourceNames = [];
$allSourceNames = [];
foreach ($joined->fetchAll(PDO::FETCH_ASSOC) as $row) {
    $row = array_change_key_case($row, CASE_LOWER);
    $category = (int)$row['category'];
    $name = (string)$row['name'];
    $sourceNames[$category][] = $name;
    $allSourceNames[$name] = true;
}
foreach ($regular['cookbook'] as $category => $item) {
    $expected = $sourceNames[(int)$category] ?? [];
    $actual = $item['data'] ?? [];
    sort($expected, SORT_STRING); sort($actual, SORT_STRING);
    if ($actual !== $expected || (int)$item['num'] !== count(array_unique($expected)))
        throw new RuntimeException('ControlScreen supply cookbook differs from recipes/dishes');
}
foreach ($school['cookbook'] as $item) {
    foreach ($item['data'] as $name) {
        if (!isset($allSourceNames[(string)$name]))
            throw new RuntimeException('School supply dish lacks source recipe');
    }
}
$schoolDishCount = array_sum(array_map(static function ($item): int {
    return (int)$item['num'];
}, $school['cookbook']));
$ingredientSum = array_sum(array_map('intval', $ingredient));
if (count($recipeRows) === 0 || $schoolDishCount === 0 || $ingredientSum === 0) {
    throw new RuntimeException('ControlScreen intended nonempty batch is empty');
}
$allDishNames = array_fill_keys($db->query('SELECT name FROM ydy_dishes')
    ->fetchAll(PDO::FETCH_COLUMN), true);
$recommendStats = [];
foreach (['recommend', 'recommend_v1'] as $action) {
    $payload = $http('/m/controlScreen/' . $action, 'POST', $screenForm)['data'];
    $items = array_values((array)$payload);
    if (!$items) throw new RuntimeException('ControlScreen recommendation unexpectedly empty');
    $named = 0;
    foreach ($items as $item) {
        $keys = is_array($item) ? array_keys($item) : [];
        sort($keys, SORT_STRING);
        if ($keys !== ['dishes', 'message', 'section']
            || !is_array($item['dishes']) || !is_array($item['message'])
            || !is_array($item['section'])) {
            throw new RuntimeException('ControlScreen recommendation item contract drift');
        }
        $name = trim((string)($item['dishes']['name'] ?? ''));
        if ($name !== '') {
            if (!isset($allDishNames[$name]))
                throw new RuntimeException('Recommended dish missing from original dishes table');
            $named++;
        }
    }
    $recommendStats[$action] = ['items' => count($items),
        'named_dishes_source_found' => $named];
}
echo json_encode(['lane' => $lane, 'staff_names_http' => 200,
    'staff_name_total' => $sourceNamesTotal,
    'staff_name_page_count' => count($source),
    'staff_name_page_source_equal' => true,
    'board_http' => 200, 'board_total_staff' => $sourceStaffTotal,
    'board_days' => count($board['days']),
    'board_displayed_menu_count' => $displayed,
    'board_source_menu_row_count' => count($rows),
    'board_each_dish_source_found' => true,
    'board_birthday_count' => count($board['birthday_people'] ?? []),
    'board_birthday_source_count' => $birthdaySource,
    'board_menu_type_signatures' => array_keys($menuTypes),
    'surplus_http' => 200, 'surplus_equipment_rows' => count($equipments),
    'surplus_displayed_sides' => count($actualCodes),
    'surplus_source_codes_equal' => true,
    'surplus_status_counts' => [
        (int)$surplusCount['normal'], (int)$surplusCount['lack'],
        (int)$surplusCount['exception']],
    'surplus_type_signatures' => array_keys($surplusTypes),
    'operation_cached_tips_count' => $operationCachedTips,
    'control_screen_restaurant' => $screenRestaurant,
    'control_screen_meal_times' => $mealTimes,
    'control_screen_recipe_rows' => count($recipeRows),
    'control_screen_regular_cookbook_source_equal' => true,
    'control_screen_school_names_source_found' => true,
    'control_screen_cuisine_counts_source_equal' => true,
    'control_screen_school_dish_count' => $schoolDishCount,
    'control_screen_offer_ingredient_sum' => $ingredientSum,
    'control_screen_recommendations' => $recommendStats,
    'business_dml' => 0], JSON_UNESCAPED_SLASHES), PHP_EOL;
