import type { Marker, SwitchType } from './types';
import { ZOOM_DEFAULT } from './types';

export const app = $state({
  markers: [] as Marker[],
  selectedIds: new Set<string>(),
  isPlaying: false,
  currentTime: 0,
  duration: 0,
  fps: 30,
  pixelsPerSecond: ZOOM_DEFAULT,
  scrollLeft: 0,
  activeSwitch: 'mxbrown' as SwitchType,
  videoUrl: null as string | null,
  videoName: null as string | null,
  timelineWidth: 800,
  previewSpeed: 1,
});

let markerCounter = 0;

export function createMarkerId(): string {
  markerCounter += 1;
  return `m${markerCounter}`;
}

export function setMarkers(value: Marker[]) {
  app.markers = value;
  const maxId = value.reduce((max, m) => {
    const num = parseInt(m.id.replace(/\D/g, ''), 10);
    return Number.isFinite(num) ? Math.max(max, num) : max;
  }, 0);
  markerCounter = maxId;
}

export function setSelectedIds(ids: Set<string>) {
  app.selectedIds = ids;
}

export function setCurrentTime(value: number) {
  app.currentTime = value;
}

export function setDuration(value: number) {
  app.duration = value;
}

export function setIsPlaying(value: boolean) {
  app.isPlaying = value;
}

export function setFps(value: number) {
  app.fps = value;
}

export function setPreviewSpeed(value: number) {
  app.previewSpeed = Math.max(0.25, Math.min(2, value));
}

export function setPixelsPerSecond(value: number) {
  app.pixelsPerSecond = value;
}

export function setScrollLeft(value: number) {
  app.scrollLeft = value;
}

export function setActiveSwitch(value: SwitchType) {
  app.activeSwitch = value;
}

export function setTimelineWidth(value: number) {
  app.timelineWidth = value;
}

export function addMarker(time: number, key: string, code?: string): Marker {
  const marker: Marker = { id: createMarkerId(), time, key, code };
  app.markers = [...app.markers, marker].sort((a, b) => a.time - b.time);
  return marker;
}

export function updateMarker(
  id: string,
  patch: Partial<Pick<Marker, 'time' | 'key' | 'code' | 'releaseTime'>>,
) {
  app.markers = app.markers
    .map((m) => (m.id === id ? { ...m, ...patch } : m))
    .sort((a, b) => a.time - b.time);
}

export function setMarkerTimes(updates: Map<string, number>) {
  app.markers = app.markers
    .map((m) => {
      const time = updates.get(m.id);
      return time === undefined ? m : { ...m, time };
    })
    .sort((a, b) => a.time - b.time);
}

export function deleteMarkers(ids: Set<string>) {
  app.markers = app.markers.filter((m) => !ids.has(m.id));
  const next = new Set(app.selectedIds);
  for (const id of ids) next.delete(id);
  app.selectedIds = next;
}

export function selectAll() {
  app.selectedIds = new Set(app.markers.map((m) => m.id));
}

export function toggleSelection(id: string, additive: boolean) {
  const next = additive ? new Set(app.selectedIds) : new Set<string>();
  if (next.has(id)) next.delete(id);
  else next.add(id);
  app.selectedIds = next;
}

export function setVideoUrl(url: string | null, name: string | null = null) {
  if (app.videoUrl) URL.revokeObjectURL(app.videoUrl);
  app.videoUrl = url;
  app.videoName = name;
}

export function snapToFrame(time: number): number {
  const frameDuration = 1 / app.fps;
  return Math.round(time / frameDuration) * frameDuration;
}

export function nudgeSelected(deltaFrames: number) {
  if (app.selectedIds.size === 0) return;
  const frameDuration = 1 / app.fps;
  const delta = deltaFrames * frameDuration;
  app.markers = app.markers
    .map((m) => {
      if (!app.selectedIds.has(m.id)) return m;
      const next = Math.max(0, Math.min(app.duration || Infinity, m.time + delta));
      return { ...m, time: snapToFrame(next) };
    })
    .sort((a, b) => a.time - b.time);
}
