/**
 * TutorialDock frontend — boot sequence, tick loop, global wiring.
 * Orchestrates all modules and holds cross-module callbacks.
 */
import '@fortawesome/fontawesome-free/css/all.min.css';
import '@fontsource/bricolage-grotesque/500.css';
import '@fontsource/bricolage-grotesque/600.css';
import '@fontsource/bricolage-grotesque/700.css';
import '@fontsource/inter/400.css';
import '@fontsource/inter/500.css';
import '@fontsource/inter/600.css';
import '@fontsource/inter/700.css';
import '@fontsource/space-mono/400.css';
import '@fontsource/space-mono/700.css';
import './styles/main.css';
import './styles/player.css';
import './styles/playlist.css';
import './styles/panels.css';
import './styles/components.css';
import './styles/animations.css';

import { api } from './api';
import type { LibraryInfo } from './types';
import {
  library, currentIndex, prefs, suppressTick, lastTick,
  setLibrary, setCurrentIndex, setPrefs, setSuppressTick, setLastTick,
  clamp, cb, currentItem,
} from './store';

import {
  initPlayer, loadVideoSrc, updatePlayPauseIcon, updateTimeReadout,
  updateSeekFill, updateVolFill, updateVideoOverlay, updateSpeedIcon,
  setVolume, setPlaybackRate, buildSpeedMenu, isPlaying, getVideoTime,
  getVideoDuration, getPlayer, isVolDragging,
  toggleMute, toggleFullscreen, showSeekFeedback, cycleSpeed,
} from './player';

import { initPlaylist, renderList, isDragging } from './playlist';
import { initSubtitles, refreshSubtitles, clearSubtitles } from './subtitles';
import {
  initUI, applyZoom, applySplit, applyDockSplit,
  updateInfoPanel, updateOverall, updateNowHeader,
  loadNoteForCurrent, refreshCurrentVideoMeta, notify,
  setOnTopChecked, setAutoplayChecked,
} from './ui';
import { initTooltips } from './tooltips';

// ---- Wire cross-module callbacks ----
cb.loadIndex = loadIndex;
cb.renderList = renderList;
cb.updateInfoPanel = updateInfoPanel;
cb.updateOverall = updateOverall;
cb.notify = notify;
cb.refreshCurrentVideoMeta = refreshCurrentVideoMeta;
cb.onLibraryLoaded = onLibraryLoaded;
cb.buildSpeedMenu = buildSpeedMenu;

// ---- Boot ----

async function boot(): Promise<void> {
  // Init all modules
  initPlayer();
  initPlaylist();
  initSubtitles();
  initUI();
  initTooltips();

  // Load prefs
  const pres = await api.getPrefs();
  const p: Record<string, any> = (pres && pres.ok) ? (pres.prefs as any || {}) : {};
  setPrefs(p);
  p.ui_zoom = applyZoom(p.ui_zoom || 1.0);
  p.split_ratio = applySplit(p.split_ratio || 0.62);
  p.dock_ratio = applyDockSplit(p.dock_ratio || 0.62);
  setOnTopChecked(!!p.always_on_top);

  await api.setPrefs({
    ui_zoom: p.ui_zoom,
    split_ratio: p.split_ratio,
    dock_ratio: p.dock_ratio,
    always_on_top: !!p.always_on_top,
  });

  // Load library
  const info = await api.getLibrary();
  if (info && info.ok) {
    await onLibraryLoaded(info, true);
    notify('Ready.');
    return;
  }

  updateOverall();
  updateTimeReadout();
  updatePlayPauseIcon();
  updateInfoPanel();
  buildSpeedMenu(1.0);
  notify('Open a folder to begin.');
  document.title = 'TutorialVault - Open a folder';
}

// ---- onLibraryLoaded ----

async function onLibraryLoaded(info: LibraryInfo, startScan: boolean): Promise<void> {
  setLibrary(info);
  setCurrentIndex(info.current_index || 0);

  clearSubtitles();

  const player = getPlayer();
  const v = clamp(Number(info.folder_volume ?? 1.0), 0, 1);
  setSuppressTick(true);
  player.volume = v;
  setVolume(v);
  setSuppressTick(false);

  const r = clamp(Number(info.folder_rate ?? 1.0), 0.25, 3);
  setPlaybackRate(r);
  buildSpeedMenu(r);

  setAutoplayChecked(!!info.folder_autoplay);

  updateOverall();
  renderList();
  updateInfoPanel();
  document.title = info?.folder ? `${info.folder} - TutorialVault` : 'TutorialVault';

  if (startScan) {
    try { await api.startDurationScan(); } catch (_) {}
  }
  await loadIndex(currentIndex, Number(info.current_time || 0.0), true, false);
}

// ---- loadIndex ----

async function loadIndex(
  idx: number,
  timecode: number = 0.0,
  pauseAfterLoad: boolean = true,
  autoplayOnLoad: boolean = false,
): Promise<void> {
  if (!library || !library.items || library.items.length === 0) return;
  idx = Math.max(0, Math.min(idx, library.items.length - 1));
  setCurrentIndex(idx);

  const it = library.items[currentIndex] || null;
  updateNowHeader(it);
  document.title = it ? `${it.title || it.name} - TutorialVault` : 'TutorialVault';

  await api.setCurrent(currentIndex, Number(timecode || 0.0));
  renderList();
  updateInfoPanel();
  await loadNoteForCurrent();
  await refreshCurrentVideoMeta();

  await loadVideoSrc(idx, timecode, pauseAfterLoad, autoplayOnLoad, async () => {
    await refreshSubtitles();
  });
}

// ---- Tick loop ----

async function tick(): Promise<void> {
  const now = Date.now();
  if (now - lastTick < 950) return;
  setLastTick(now);

  if (library && !suppressTick) {
    const t = getVideoTime();
    const d = getVideoDuration();
    const playing = isPlaying();
    try { await api.tickProgress(currentIndex, t, d, playing); } catch (_) {}
  }

  if (now % 3000 < 1000 && !suppressTick) {
    try {
      const info = await api.getLibrary();
      if (info && info.ok) {
        const oldIndex = currentIndex;
        const oldCount = library?.items?.length || 0;
        setLibrary(info);
        setCurrentIndex(info.current_index || currentIndex);
        setAutoplayChecked(!!info.folder_autoplay);

        const player = getPlayer();
        const volSlider = document.getElementById('volSlider') as HTMLInputElement & { dragging?: boolean };
        const v = clamp(Number(info.folder_volume ?? player.volume ?? 1.0), 0, 1);
        if (!isVolDragging() && Math.abs(v - Number(volSlider.value)) > 0.001) {
          volSlider.value = String(v);
          updateVolFill();
        }

        const r = clamp(Number(info.folder_rate ?? player.playbackRate ?? 1.0), 0.25, 3);
        player.playbackRate = r;
        updateSpeedIcon(r);
        buildSpeedMenu(r);

        updateOverall();
        updateInfoPanel();
        updateNowHeader(currentItem());

        if (!isDragging() && (oldIndex !== currentIndex || oldCount !== (library?.items?.length || 0))) {
          renderList();
        }
      }
    } catch (_) {}
  }

  try { await api.saveWindowState(); } catch (_) {}
}

// ---- Keyboard shortcuts ----

// ---- Shortcut help dialog ----

let shortcutHelpOpen = false;

function toggleShortcutHelp(): void {
  const el = document.getElementById('shortcutHelp');
  if (!el) return;
  shortcutHelpOpen = !shortcutHelpOpen;
  if (shortcutHelpOpen) {
    el.style.display = 'flex';
    document.getElementById('zoomRoot')?.setAttribute('aria-hidden', 'true');
    // Focus trap: focus the panel
    const panel = el.querySelector('.shortcutHelpPanel') as HTMLElement | null;
    if (panel) { panel.tabIndex = -1; panel.focus(); }
  } else {
    el.style.display = 'none';
    document.getElementById('zoomRoot')?.removeAttribute('aria-hidden');
  }
}

function initKeyboard(): void {
  window.addEventListener('keydown', (e) => {
    // Close shortcut help on Escape or ?
    if (shortcutHelpOpen) {
      if (e.key === 'Escape' || e.key === '?') {
        e.preventDefault();
        toggleShortcutHelp();
      }
      return; // trap focus while dialog is open
    }

    // Don't capture when typing in textarea/input
    const tag = (e.target as HTMLElement).tagName;
    if (tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT') return;

    switch (e.key) {
      case ' ':
        e.preventDefault();
        { const player = getPlayer();
          if (player.paused || player.ended) player.play();
          else player.pause();
          updatePlayPauseIcon(); }
        break;
      case 'ArrowLeft':
        e.preventDefault();
        try {
          getPlayer().currentTime = Math.max(0, getPlayer().currentTime - 5);
          showSeekFeedback(-5);
        } catch (_) {}
        break;
      case 'ArrowRight':
        e.preventDefault();
        try {
          getPlayer().currentTime = Math.min(getPlayer().duration || 0, getPlayer().currentTime + 5);
          showSeekFeedback(+5);
        } catch (_) {}
        break;
      case 'ArrowUp':
        e.preventDefault();
        try {
          const p = getPlayer();
          p.volume = clamp(p.volume + 0.05, 0, 1);
          setVolume(p.volume);
        } catch (_) {}
        break;
      case 'ArrowDown':
        e.preventDefault();
        try {
          const p = getPlayer();
          p.volume = clamp(p.volume - 0.05, 0, 1);
          setVolume(p.volume);
        } catch (_) {}
        break;
      case 'f':
        e.preventDefault();
        toggleFullscreen();
        break;
      case 'm':
        e.preventDefault();
        toggleMute();
        break;
      case '[':
        e.preventDefault();
        cycleSpeed(-1);
        break;
      case ']':
        e.preventDefault();
        cycleSpeed(+1);
        break;
      case '?':
        e.preventDefault();
        toggleShortcutHelp();
        break;
    }
  });

  // Backdrop click closes shortcut help
  const helpEl = document.getElementById('shortcutHelp');
  if (helpEl) {
    helpEl.querySelector('.shortcutHelpBackdrop')?.addEventListener('click', () => {
      if (shortcutHelpOpen) toggleShortcutHelp();
    });
  }
}

// ---- Start ----

initKeyboard();
setInterval(tick, 250);
boot();
