import type { FleetServer } from '../fleet-overview.js'; import { actionLabels, type RuntimeAction } from '../provisioning.js'; import { freshStatusTimestamp } from '../server-freshness.js'; import { serverHealth } from './server-health.js'; /** UI affordances only: the queue still checks ownership, conflicts and occupancy. */ export function applicableRuntimeActions(server: FleetServer, now: number): RuntimeAction[] { const health = serverHealth(server, now).state; if (health === 'stopped') return ['start', 'rebuild']; const currentRunningContainer = server.container_state === 'running' && freshStatusTimestamp(server.container_checked_at ?? null, now) && (!server.telemetry_after || Date.parse(server.container_checked_at!) > Date.parse(server.telemetry_after)); if (health === 'online' || health === 'not-responding' && currentRunningContainer) return ['restart', 'stop', 'rebuild']; return []; } /** Counts must come from fresh observations; null must never read as an empty lobby. */ export function lifecycleImpact(action: RuntimeAction | 'destroy', players: number | null, round: number | null): string { if (action === 'start') return 'Start the existing container, then verify that the game is responding.'; const label = action === 'destroy' ? 'Removal' : actionLabels[action]; if (players === null || !Number.isSafeInteger(players) || players < 0) { return `Player count is unknown. ${label} waits for a live check confirming the lobby is empty.`; } if (players === 0) return `The lobby is currently empty. A live check will confirm this before ${label.toLowerCase()} begins.`; const subject = `${players.toLocaleString('en-US')} ${players === 1 ? 'player is' : 'players are'}`; const activity = round !== null && Number.isSafeInteger(round) && round >= 0 ? `in round ${round.toLocaleString('en-US')}` : 'currently online'; return `${subject} ${activity}. ${label} waits until the lobby is empty.`; }