import { ref, computed } from 'vue' const TICK_MS = 100 export function useReplayControls() { const isPaused = ref(true) const speed = ref(60) const scenarioStartMs = ref(0) const scenarioEndMs = ref(0) const currentMs = ref(0) let timer = null const scenarioDurationMinutes = computed(() => { const span = scenarioEndMs.value - scenarioStartMs.value return span > 0 ? span / 60_000 : 0 }) const currentOffsetMinutes = computed(() => { const span = currentMs.value - scenarioStartMs.value return span > 0 ? span / 60_000 : 0 }) const progress = computed(() => { const span = scenarioEndMs.value - scenarioStartMs.value if (span <= 0) return 0 return Math.min(100, ((currentMs.value - scenarioStartMs.value) / span) * 100) }) const formattedTime = computed(() => { const mins = currentOffsetMinutes.value const h = Math.floor(mins / 60) const m = Math.floor(mins % 60) return `${h}:${String(m).padStart(2, '0')}` }) function setScenarioBounds(startMs, endMs) { if (!Number.isFinite(startMs) || !Number.isFinite(endMs) || endMs <= startMs) return scenarioStartMs.value = startMs scenarioEndMs.value = endMs if (currentMs.value < startMs || currentMs.value > endMs) { currentMs.value = endMs } } function syncToEnd() { if (scenarioEndMs.value > scenarioStartMs.value) { currentMs.value = scenarioEndMs.value } } function pause() { isPaused.value = true stopTick() } function resume() { if (scenarioEndMs.value <= scenarioStartMs.value) return if (currentMs.value >= scenarioEndMs.value) { currentMs.value = scenarioStartMs.value } isPaused.value = false startTick() } function setSpeed(s) { speed.value = s if (s === 0) { currentMs.value = scenarioEndMs.value pause() } } function jumpToOffset(minutes) { if (scenarioEndMs.value <= scenarioStartMs.value) return const target = scenarioStartMs.value + minutes * 60_000 currentMs.value = Math.min(Math.max(target, scenarioStartMs.value), scenarioEndMs.value) } function jumpToTimestamp(iso) { if (!iso || scenarioEndMs.value <= scenarioStartMs.value) return const ms = new Date(iso).getTime() currentMs.value = Math.min(Math.max(ms, scenarioStartMs.value), scenarioEndMs.value) } function isAtOrBefore(iso) { if (!iso) return true return new Date(iso).getTime() <= currentMs.value } function tick() { if (isPaused.value || scenarioEndMs.value <= scenarioStartMs.value) return if (speed.value === 0) { currentMs.value = scenarioEndMs.value pause() return } currentMs.value = Math.min(currentMs.value + TICK_MS * speed.value, scenarioEndMs.value) if (currentMs.value >= scenarioEndMs.value) pause() } function startTick() { stopTick() timer = setInterval(tick, TICK_MS) } function stopTick() { if (timer) clearInterval(timer) timer = null } function stopPlayback() { stopTick() } return { isPaused, speed, scenarioStartMs, scenarioEndMs, currentMs, scenarioDurationMinutes, currentOffsetMinutes, progress, formattedTime, setScenarioBounds, syncToEnd, pause, resume, setSpeed, jumpToOffset, jumpToTimestamp, isAtOrBefore, stopPlayback, } }