// Pointer interaction for the waveform: click-to-seek, drag-to-scrub,
// hover indicator + tooltip with time-at-cursor. CSS variables only — no
// React state, no canvas redraws.

import { formatTime } from '../../utils/formatTime';

const HOVER_X = '--hp';
const HOVER_OPACITY = '--ho';
const TOOLTIP_LABEL = '--ht';

export type AttachSeekOptions = {
  // When the user clicks while paused/idle, also start playback. Drag scrub
  // never auto-starts (already playing or user is scrubbing without intent).
  startsPlayback?: boolean;
  onPlayRequest?: () => void;
};

export function attachSeek(
  container: HTMLElement,
  audio: HTMLAudioElement,
  options: AttachSeekOptions = {},
): () => void {
  let dragging = false;
  let movedDuringDrag = false;
  const { startsPlayback = true, onPlayRequest } = options;

  const ratioFor = (clientX: number): number => {
    const rect = container.getBoundingClientRect();
    if (rect.width === 0) return 0;
    return Math.max(0, Math.min(1, (clientX - rect.left) / rect.width));
  };

  const seekTo = (clientX: number) => {
    const dur = Number.isFinite(audio.duration) ? audio.duration : 0;
    if (dur > 0) audio.currentTime = ratioFor(clientX) * dur;
  };

  const onPointerDown = (e: PointerEvent) => {
    if (e.button !== 0 && e.pointerType === 'mouse') return;
    dragging = true;
    movedDuringDrag = false;
    container.setPointerCapture?.(e.pointerId);
    seekTo(e.clientX);
  };
  const onPointerMove = (e: PointerEvent) => {
    if (!dragging) return;
    movedDuringDrag = true;
    seekTo(e.clientX);
  };
  const onPointerEnd = (e: PointerEvent) => {
    if (!dragging) return;
    const wasDrag = movedDuringDrag;
    dragging = false;
    movedDuringDrag = false;
    try {
      container.releasePointerCapture?.(e.pointerId);
    } catch {
      // ignore
    }
    // Click (not drag) while paused → start playback at the seek target.
    if (!wasDrag && startsPlayback && (audio.paused || audio.ended)) {
      onPlayRequest?.();
    }
  };

  container.addEventListener('pointerdown', onPointerDown);
  container.addEventListener('pointermove', onPointerMove);
  container.addEventListener('pointerup', onPointerEnd);
  container.addEventListener('pointercancel', onPointerEnd);

  return () => {
    container.removeEventListener('pointerdown', onPointerDown);
    container.removeEventListener('pointermove', onPointerMove);
    container.removeEventListener('pointerup', onPointerEnd);
    container.removeEventListener('pointercancel', onPointerEnd);
  };
}

export function attachHover(container: HTMLElement, audio: HTMLAudioElement): () => void {
  const tooltip = container.querySelector<HTMLElement>('[data-audioplayer-time-tip]');

  const onMove = (e: PointerEvent) => {
    const rect = container.getBoundingClientRect();
    if (rect.width === 0) return;
    const x = Math.max(0, Math.min(rect.width, e.clientX - rect.left));
    container.style.setProperty(HOVER_X, `${x}px`);
    container.style.setProperty(HOVER_OPACITY, '1');
    if (tooltip) {
      const dur = Number.isFinite(audio.duration) ? audio.duration : 0;
      const t = (x / rect.width) * dur;
      tooltip.textContent = formatTime(t);
      tooltip.style.setProperty(TOOLTIP_LABEL, '1');
    }
  };
  const onLeave = () => {
    container.style.setProperty(HOVER_OPACITY, '0');
    if (tooltip) tooltip.style.setProperty(TOOLTIP_LABEL, '0');
  };

  container.addEventListener('pointermove', onMove);
  container.addEventListener('pointerleave', onLeave);
  return () => {
    container.removeEventListener('pointermove', onMove);
    container.removeEventListener('pointerleave', onLeave);
  };
}
