<?php
declare(strict_types=1);

// Bounded, SELECT-only existing dual-menu scan. Never outputs source IDs/names.
$lane = (string)getenv('CDX_EM_DUAL_LANE');
if (!in_array($lane, ['A', 'B', 'C'], true)
    || count($argv) !== 2 || ($argv[1] ?? '') !== '--scan'
    || (string)getenv('CDX_EM_DUAL_SCAN') !== 'BOUNDED_ACTIVE_DUAL_SELECT_ONLY_V1'
    || !hash_equals((string)hash_file('sha256', __FILE__),
        (string)getenv('CDX_EM_DUAL_SCAN_SHA'))) {
    echo json_encode(['status' => 'default-deny', 'db_connected' => false,
        'business_http_sent' => false, 'dml_sent' => false]), PHP_EOL;
    exit(78);
}
$sourceProbe = __DIR__ . '/plan_dual_meal_window.php';
if (!hash_equals('49f480904a2e563c02264d6410a8c517afe4b8bb2c70928083339152f71d58bf',
    (string)hash_file('sha256', $sourceProbe))) {
    throw new RuntimeException('Approved identity/source probe drift');
}
putenv('CDX_EM_DUAL_WINDOW=OWNED_DUAL_WINDOW_SELECT_ONLY_V1');
putenv('CDX_EM_DUAL_WINDOW_SHA=49f480904a2e563c02264d6410a8c517afe4b8bb2c70928083339152f71d58bf');
$outerArgv = $argv;
$argv[1] = '--preflight';
ob_start();
require $sourceProbe;
$identityText = (string)ob_get_clean();
$argv = $outerArgv;
restore_exception_handler();
$identity = json_decode(trim($identityText), true);
if (!is_array($identity) || ($identity['status'] ?? null) !== 'select_only_pass'
    || ($identity['lane'] ?? null) !== $lane) {
    throw new RuntimeException('Current-lane source probe did not pass');
}
set_exception_handler(static function (Throwable $error): void {
    echo json_encode(['status' => 'redacted_stop',
        'error_class' => get_class($error), 'code' => (string)$error->getCode(),
        'business_http_sent' => false, 'dml_sent' => false]), PHP_EOL;
    exit(2);
});
$candidates = $db->query('SELECT m.LEFT_RESTAURANT_ID,m.RIGHT_RESTAURANT_ID,'
    . ' l.MORNING_START,l.MORNING_END,l.NOON_START,l.NOON_END,'
    . ' l.NIGHT_START,l.NIGHT_END'
    . ' FROM ' . $table('electronic_menu') . ' m'
    . ' JOIN ' . $table('restaurants') . ' l ON l.ID=m.LEFT_RESTAURANT_ID'
    . ' JOIN ' . $table('restaurants') . ' r ON r.ID=m.RIGHT_RESTAURANT_ID'
    . ' WHERE m.STORE_ID=10001 AND m.STATUS=1 AND m.IS_DELETE=0'
    . ' AND m.DISPLAY_MODE=2 AND m.RIGHT_RESTAURANT_ID>0'
    . ' AND l.STATUS=1 AND l.IS_DELETE=2'
    . ' AND r.STATUS=1 AND r.IS_DELETE=2 ORDER BY m.ID')
    ->fetchAll(PDO::FETCH_ASSOC);
$limit = $lane === 'C' ? 2 : 7;
if ($candidates === [] || count($candidates) > $limit) {
    throw new RuntimeException('Existing dual-candidate scope changed');
}
$ids = [];
foreach ($candidates as $row) {
    $a = (int)$row['left_restaurant_id'];
    $b = (int)$row['right_restaurant_id'];
    if ($a <= 0 || $b <= 0 || $a === $b) {
        throw new RuntimeException('Candidate relation invalid');
    }
    $ids[$a] = $a;
    $ids[$b] = $b;
}
if (count($ids) > 2 * $limit) throw new RuntimeException('Restaurant scope too large');
$placeholders = implode(',', array_fill(0, count($ids), '?'));
$query = $db->prepare('SELECT r.RESTAURANT_ID,r.MEAL_TIMES,COUNT(*) AS N'
    . ' FROM ' . $table('recipes') . ' r JOIN ' . $table('dishes')
    . ' d ON d.UUID=r.DISHES_UUID WHERE r.MENU_DATE=?'
    . ' AND r.RESTAURANT_ID IN (' . $placeholders . ')'
    . ' AND r.MEAL_TIMES BETWEEN 1 AND 4'
    . ' AND d.STATUS=1 AND d.IS_DEL=1'
    . ' GROUP BY r.RESTAURANT_ID,r.MEAL_TIMES');
$query->execute(array_merge([$day], array_values($ids)));
$counts = [];
foreach ($query->fetchAll(PDO::FETCH_ASSOC) as $row) {
    $rid = (int)$row['restaurant_id'];
    $meal = (int)$row['meal_times'];
    if (!isset($ids[$rid]) || $meal < 1 || $meal > 4) {
        throw new RuntimeException('Out-of-scope aggregate row');
    }
    $counts[$rid][$meal] = (int)$row['n'];
}
$mealAt = static function (array $row, string $at): int {
    foreach (['morning' => 1, 'noon' => 2, 'night' => 3] as $name => $meal) {
        $from = substr((string)($row[$name . '_start'] ?? ''), 0, 5) . ':00';
        $to = substr((string)($row[$name . '_end'] ?? ''), 0, 5) . ':59';
        if (!preg_match('/^\d\d:\d\d:00$/D', $from)
            || !preg_match('/^\d\d:\d\d:59$/D', $to)) {
            throw new RuntimeException('Candidate meal metadata invalid');
        }
        if ($at >= $from && $at <= $to) return $meal;
    }
    return 4;
};
$positiveAt = static function (string $at) use ($candidates, $counts, $mealAt): array {
    $any = 0;
    $leftPositive = 0;
    $rightPositive = 0;
    $bothPositive = 0;
    $maxLeft = 0;
    $maxRight = 0;
    foreach ($candidates as $row) {
        $meal = $mealAt($row, $at);
        $leftCount = (int)($counts[(int)$row['left_restaurant_id']][$meal] ?? 0);
        $rightCount = (int)($counts[(int)$row['right_restaurant_id']][$meal] ?? 0);
        if ($leftCount + $rightCount > 0) $any++;
        if ($leftCount > 0) $leftPositive++;
        if ($rightCount > 0) $rightPositive++;
        if ($leftCount > 0 && $rightCount > 0) $bothPositive++;
        $maxLeft = max($maxLeft, $leftCount);
        $maxRight = max($maxRight, $rightCount);
    }
    return [$any, $leftPositive, $rightPositive, $bothPositive, $maxLeft, $maxRight];
};
$now = $positiveAt($clock);
$clockSeconds = ((int)substr($clock, 0, 2) * 3600)
    + ((int)substr($clock, 3, 2) * 60) + (int)substr($clock, 6, 2);
$startMinute = (int)ceil($clockSeconds / 60);
$futureStart = null;
$futureEnd = null;
for ($minute = $startMinute; $minute < 1440; $minute++) {
    $at = sprintf('%02d:%02d:00', intdiv($minute, 60), $minute % 60);
    if ($positiveAt($at)[0] > 0) {
        if ($futureStart === null) $futureStart = $at;
        $futureEnd = sprintf('%02d:%02d:59', intdiv($minute, 60), $minute % 60);
    } elseif ($futureStart !== null) {
        break;
    }
}
echo json_encode(['status' => 'bounded_select_pass', 'lane' => $lane,
    'business_date' => $day, 'clock' => $clock,
    'candidate_menu_count' => count($candidates),
    'distinct_restaurant_count' => count($ids),
    'current_positive_candidate_count' => $now[0],
    'current_left_positive_candidate_count' => $now[1],
    'current_right_positive_candidate_count' => $now[2],
    'current_both_positive_candidate_count' => $now[3],
    'current_max_left_valid_dishes' => $now[4],
    'current_max_right_valid_dishes' => $now[5],
    'next_today_positive_window' => [$futureStart, $futureEnd],
    'business_http_sent' => false, 'dml_sent' => false],
    JSON_UNESCAPED_SLASHES), PHP_EOL;
