diff --git a/shared/composables/flightlab/useFlightLabEngine.ts b/shared/composables/flightlab/useFlightLabEngine.ts new file mode 100644 index 0000000..bbec6c6 --- /dev/null +++ b/shared/composables/flightlab/useFlightLabEngine.ts @@ -0,0 +1,99 @@ +// shared/composables/flightlab/useFlightLabEngine.ts +import { ref, computed } from 'vue' +import type { FlightLabPhase, FlightLabScenario, FlightLabButton } from '../../data/flightlab/types' + +export function useFlightLabEngine(scenario: FlightLabScenario) { + const currentPhaseId = ref(scenario.phases[0]?.id ?? '') + const isPaused = ref(false) + const history = ref>([]) + const startedAt = ref(Date.now()) + + const phasesMap = computed(() => { + const map = new Map() + for (const phase of scenario.phases) { + map.set(phase.id, phase) + } + return map + }) + + const currentPhase = computed(() => phasesMap.value.get(currentPhaseId.value) ?? null) + + // Count only main phases (not comfort/info branches) for progress + const mainPhaseIds = ['welcome', 'briefing', 'runway', 'engines_pre', 'engines_spool', 'takeoff_roll', 'rotation', 'gear_retract', 'climb', 'climb_high', 'leveloff', 'debrief', 'end'] + + const progress = computed(() => { + const idx = mainPhaseIds.indexOf(currentPhaseId.value) + if (idx === -1) { + // We're in a sub-phase, find the closest main phase from history + for (let i = history.value.length - 1; i >= 0; i--) { + const mainIdx = mainPhaseIds.indexOf(history.value[i].phaseId) + if (mainIdx !== -1) return Math.round((mainIdx / (mainPhaseIds.length - 1)) * 100) + } + return 0 + } + return Math.round((idx / (mainPhaseIds.length - 1)) * 100) + }) + + const isFinished = computed(() => currentPhaseId.value === 'end') + + function selectOption(button: FlightLabButton) { + if (isPaused.value) return + history.value.push({ + phaseId: currentPhaseId.value, + buttonId: button.id, + timestamp: Date.now(), + }) + goToPhase(button.next) + return button + } + + function goToPhase(phaseId: string) { + if (phasesMap.value.has(phaseId)) { + currentPhaseId.value = phaseId + } + } + + function restart() { + currentPhaseId.value = scenario.phases[0]?.id ?? '' + isPaused.value = false + history.value = [] + startedAt.value = Date.now() + } + + function pause() { isPaused.value = true } + function resume() { isPaused.value = false } + + function skipForward() { + const idx = mainPhaseIds.indexOf(currentPhaseId.value) + if (idx >= 0 && idx < mainPhaseIds.length - 1) { + goToPhase(mainPhaseIds[idx + 1]) + } + } + + function skipBack() { + const idx = mainPhaseIds.indexOf(currentPhaseId.value) + if (idx > 0) { + goToPhase(mainPhaseIds[idx - 1]) + } + } + + return { + // State + currentPhaseId, + currentPhase, + isPaused, + history, + progress, + isFinished, + startedAt, + scenario, + // Actions + selectOption, + goToPhase, + restart, + pause, + resume, + skipForward, + skipBack, + } +}