import { saveProgress } from "./progress";
import { state } from "./state";
import { safeLocalStorage } from "./storage";

export const formatTime = (seconds: number): string => {
  if (!Number.isFinite(seconds) || seconds < 0) {
    return "00:00";
  }
  const mins = Math.floor(seconds / 60);
  const secs = Math.floor(seconds % 60);
  return `${mins.toString().padStart(2, "0")}:${secs.toString().padStart(2, "0")}`;
};

/** Shows the controls overlay and schedules auto-hide after 2s if playing. */
export const showControls = (): void => {
  state.elements.container.classList.add("show-controls");
  window.clearTimeout(state.timers.playerControlsTimeout);
  state.timers.playerControlsTimeout = window.setTimeout(() => {
    if (!state.ui.isScrubbing && !state.elements.video.paused) {
      state.elements.container.classList.remove("show-controls");
    }
  }, 2000);
};

// seek relative to current position
export const seekBy = (delta: number): void => {
  if (state.elements.video.duration <= 0) {
    return;
  }
  state.elements.video.currentTime = Math.max(
    0,
    Math.min(state.elements.video.duration, state.elements.video.currentTime + delta),
  );
  showControls();
};

export const togglePlayPause = (): void => {
  if (state.elements.video.paused) {
    state.elements.video.play();
  } else {
    state.elements.video.pause();
  }
};

// toggle mute, restoring previous volume
export const toggleMute = (): void => {
  if (state.elements.video.muted || state.elements.video.volume === 0) {
    const restored = state.playback.lastKnownVolume > 0 ? state.playback.lastKnownVolume : 1;
    state.elements.video.muted = false;
    state.elements.video.volume = restored;
  } else {
    state.playback.lastKnownVolume =
      state.elements.video.volume > 0
        ? state.elements.video.volume
        : state.playback.lastKnownVolume;
    state.elements.video.muted = true;
  }
};

// set volume (0-1), auto-unmute
export const setVolume = (value: number): void => {
  state.elements.video.volume = Math.max(0, Math.min(1, value));
  state.elements.video.muted = value === 0;
  if (value > 0) {
    state.playback.lastKnownVolume = value;
  }
};

export const toggleFullscreen = (): void => {
  if (document.fullscreenElement) {
    document.exitFullscreen();
    return;
  }
  state.elements.container.requestFullscreen?.();
};

// syncs volume slider, underline, and mute icon
const syncVolumeUI = (): void => {
  const { volumeRange, volumeUnderline } = getControls();
  const value = state.elements.video.muted ? 0 : Math.round(state.elements.video.volume * 100);
  if (volumeRange) {
    volumeRange.value = String(value);
    volumeRange.style.setProperty("--volume-percent", `${value}%`);
  }
  if (volumeUnderline) {
    volumeUnderline.style.height = `${value}%`;
  }
  updateMuteIcons(state.elements.video.muted || state.elements.video.volume === 0);
};

const VOLUME_STORAGE_KEY = "player-volume";

const parseStoredVolume = (raw: string | null): number | null => {
  if (!raw) {
    return null;
  }
  const v = Number.parseFloat(raw);
  if (!Number.isFinite(v)) {
    return null;
  }
  if (v < 0 || v > 1) {
    return null;
  }
  return v;
};

const applyStoredVolume = (): void => {
  const stored = parseStoredVolume(safeLocalStorage.getItem(VOLUME_STORAGE_KEY));
  if (stored === null) {
    return;
  }

  state.elements.video.volume = stored;
  state.elements.video.muted = stored === 0;
  if (stored > 0) {
    state.playback.lastKnownVolume = stored;
  }
};

let volumeSaveTimer: number | undefined;
const schedulePersistVolume = (): void => {
  window.clearTimeout(volumeSaveTimer);
  volumeSaveTimer = window.setTimeout(() => {
    if (!Number.isFinite(state.elements.video.volume)) {
      return;
    }
    const clamped = Math.max(0, Math.min(1, state.elements.video.volume));
    safeLocalStorage.setItem(VOLUME_STORAGE_KEY, clamped.toFixed(3));
  }, 250);
};

type Controls = {
  playPause: HTMLButtonElement | null;
  muteBtn: HTMLButtonElement | null;
  volumePanel: HTMLElement | null;
  volumeRange: HTMLInputElement | null;
  volumeUnderline: HTMLElement | null;
  backwardBtn: HTMLButtonElement | null;
  forwardBtn: HTMLButtonElement | null;
  fullscreenBtn: HTMLButtonElement | null;
  iconPlay: SVGElement | null;
  iconPause: SVGElement | null;
  iconVolume: SVGElement | null;
  iconMuted: SVGElement | null;
  skipSegmentBtn: HTMLButtonElement | null;
  subtitleText: HTMLElement | null;
  autoplayBtn: HTMLInputElement | null;
};

let controlsCache: Controls | null = null;

const getControls = (): Controls => {
  if (controlsCache) {
    return controlsCache;
  }
  const c = state.elements.container;
  controlsCache = {
    playPause: c.querySelector("[data-play-pause]"),
    muteBtn: c.querySelector("[data-mute]"),
    volumePanel: c.querySelector("[data-volume-panel]"),
    volumeRange: c.querySelector("[data-volume-range]"),
    volumeUnderline: c.querySelector("[data-volume-underline]"),
    backwardBtn: c.querySelector("[data-backward]"),
    forwardBtn: c.querySelector("[data-forward]"),
    fullscreenBtn: c.querySelector("[data-fullscreen]"),
    iconPlay: c.querySelector("[data-icon-play]"),
    iconPause: c.querySelector("[data-icon-pause]"),
    iconVolume: c.querySelector("[data-icon-volume]"),
    iconMuted: c.querySelector("[data-icon-muted]"),
    skipSegmentBtn: c.querySelector("[data-skip]"),
    subtitleText: c.querySelector("[data-subtitle-text]"),
    autoplayBtn: document.querySelector("[data-autoplay]"),
  };
  return controlsCache;
};

const updatePlayPauseIcons = (isPlaying: boolean): void => {
  const { iconPlay, iconPause } = getControls();
  iconPlay?.classList.toggle("hidden", isPlaying);
  iconPause?.classList.toggle("hidden", !isPlaying);
};

const updateMuteIcons = (isMuted: boolean): void => {
  const { iconVolume, iconMuted } = getControls();
  iconVolume?.classList.toggle("hidden", isMuted);
  iconMuted?.classList.toggle("hidden", !isMuted);
};

/** Binds click handlers to player control buttons. Sets up video event listeners for icon sync. */
export const setupControls = (): void => {
  applyStoredVolume();

  const {
    playPause,
    muteBtn,
    volumePanel,
    volumeRange,
    backwardBtn,
    forwardBtn,
    fullscreenBtn,
    skipSegmentBtn,
  } = getControls();

  // play/pause on button and video click
  playPause?.addEventListener("click", () => {
    togglePlayPause();
    showControls();
  });
  state.elements.video.addEventListener("click", () => {
    togglePlayPause();
    showControls();
  });

  muteBtn?.addEventListener("click", () => {
    toggleMute();
    showControls();
  });

  // volume slider
  volumeRange?.addEventListener("input", () => {
    const value = Number(volumeRange.value) / 100;
    setVolume(value);
    showControls();
  });
  // dragging class for visual feedback
  volumeRange?.addEventListener("pointerdown", () => volumePanel?.classList.add("is-dragging"));
  window.addEventListener("pointerup", () => volumePanel?.classList.remove("is-dragging"));

  backwardBtn?.addEventListener("click", () => {
    seekBy(-10);
  });
  forwardBtn?.addEventListener("click", () => {
    seekBy(10);
  });

  fullscreenBtn?.addEventListener("click", () => {
    toggleFullscreen();
    showControls();
  });

  // skip intro/outro button
  skipSegmentBtn?.addEventListener("click", () => {
    if (!state.skip.activeSegment) {
      return;
    }
    state.elements.video.currentTime = state.skip.activeSegment.end + 0.01;
    showControls();
  });

  // fullscreen change handler
  document.addEventListener("fullscreenchange", () => {
    state.ui.isFullscreen = Boolean(document.fullscreenElement);
    state.elements.container.classList.toggle("fullscreen", state.ui.isFullscreen);
    if (state.ui.isFullscreen) {
      showControls();
    }
  });

  // icon sync on state changes
  state.elements.video.addEventListener("play", () => {
    updatePlayPauseIcons(true);
    showControls();
  });
  state.elements.video.addEventListener("pause", () => {
    updatePlayPauseIcons(false);
    showControls();
    saveProgress().catch((error) => {
      console.error("pause control progress save failed:", error);
    });
  });
  state.elements.video.addEventListener("volumechange", () => {
    syncVolumeUI();
    schedulePersistVolume();
  });

  // mouse move in container shows controls
  state.elements.container.addEventListener("mousemove", showControls);

  // initial sync — check actual video state since inline script may have started playback
  updatePlayPauseIcons(!state.elements.video.paused);
  syncVolumeUI();
};
