'use client';

import { useRef, useCallback, useEffect, useState } from 'react';
import { Comment } from '../../lib/api';
import { formatTimecode } from '../../lib/format';

interface Props {
  duration: number;
  currentTime: number;
  fps: number;
  comments: Comment[];
  onSeek: (time: number) => void;
  onCommentClick: (comment: Comment) => void;
}

export function Timeline({ duration, currentTime, fps, comments, onSeek, onCommentClick }: Props) {
  const trackRef = useRef<HTMLDivElement>(null);

  // ── Drag state ─────────────────────────────────────────────────────────────
  // draggingRef: controls video seeks during drag (written by handlers, read by effect)
  const draggingRef = useRef(false);
  // isDragging: React state — controls visual active state (scrubber scale, tooltip)
  const [isDragging, setIsDragging] = useState(false);
  // draggedTime: tracks the visual position of the scrubber during drag, decoupled from
  // the actual video time so the scrubber never lags behind the cursor
  const [draggedTime, setDraggedTime] = useState(currentTime);
  // tooltipX: CSS left position (%) for tooltip positioning during drag
  const [tooltipX, setTooltipX] = useState(0);

  // ── Sync display time when NOT dragging ──────────────────────────────────
  useEffect(() => {
    if (draggingRef.current) return;
    setDraggedTime(currentTime);
  }, [currentTime]);

  // ── Cursor → time ────────────────────────────────────────────────────────
  const cursorToTime = useCallback((clientX: number): number | null => {
    if (!trackRef.current) return null;
    const rect = trackRef.current.getBoundingClientRect();
    const ratio = Math.max(0, Math.min(1, (clientX - rect.left) / rect.width));
    return ratio * duration;
  }, [duration]);

  const cursorToPercent = useCallback((clientX: number): number => {
    if (!trackRef.current) return 0;
    const rect = trackRef.current.getBoundingClientRect();
    return Math.max(0, Math.min(100, ((clientX - rect.left) / rect.width) * 100));
  }, []);

  // ── Core seek — updates display + video ──────────────────────────────────
  const seekTo = useCallback((t: number) => {
    const clamped = Math.max(0, Math.min(duration, t));
    setDraggedTime(clamped);
    onSeek(clamped);
  }, [duration, onSeek]);

  // ── Mouse handlers (desktop) ─────────────────────────────────────────────
  const handleMouseDown = useCallback((e: React.MouseEvent) => {
    if (e.button !== 0) return;
    e.preventDefault();

    // Reset stale drag state
    draggingRef.current = false;
    setIsDragging(false);

    // Begin drag
    draggingRef.current = true;
    setIsDragging(true);

    const t = cursorToTime(e.clientX);
    if (t === null) return;
    seekTo(t);
    setTooltipX(cursorToPercent(e.clientX));

    // Capture pointer so mouseup always fires even if cursor leaves the track
    trackRef.current?.setPointerCapture((e as unknown as React.PointerEvent).pointerId);
  }, [cursorToTime, cursorToPercent, seekTo]);

  const handleMouseMove = useCallback((e: MouseEvent) => {
    if (!draggingRef.current) return;
    const t = cursorToTime(e.clientX);
    if (t === null) return;
    seekTo(t);
    setTooltipX(cursorToPercent(e.clientX));
  }, [cursorToTime, cursorToPercent, seekTo]);

  const handleMouseUp = useCallback((e: MouseEvent) => {
    if (!draggingRef.current) return;
    draggingRef.current = false;
    setIsDragging(false);
    const t = cursorToTime(e.clientX);
    if (t !== null) seekTo(t);
  }, [cursorToTime, seekTo]);

  // ── Touch handlers (mobile) ───────────────────────────────────────────────
  const handleTouchStart = useCallback((e: React.TouchEvent) => {
    if (e.touches.length !== 1) return;
    const touch = e.touches[0];
    draggingRef.current = true;
    setIsDragging(true);
    const t = cursorToTime(touch.clientX);
    if (t !== null) seekTo(t);
    setTooltipX(cursorToPercent(touch.clientX));
  }, [cursorToTime, cursorToPercent, seekTo]);

  const handleTouchMove = useCallback((e: React.TouchEvent) => {
    if (!draggingRef.current || e.touches.length !== 1) return;
    const touch = e.touches[0];
    const t = cursorToTime(touch.clientX);
    if (t !== null) seekTo(t);
    setTooltipX(cursorToPercent(touch.clientX));
  }, [cursorToTime, cursorToPercent, seekTo]);

  const handleTouchEnd = useCallback((e: React.TouchEvent) => {
    if (!draggingRef.current) return;
    draggingRef.current = false;
    setIsDragging(false);
    const touch = e.changedTouches[0];
    if (touch) {
      const t = cursorToTime(touch.clientX);
      if (t !== null) seekTo(t);
    }
  }, [cursorToTime, seekTo]);

  // ── Global mouse listeners (desktop drag) ─────────────────────────────────
  useEffect(() => {
    window.addEventListener('mousemove', handleMouseMove);
    window.addEventListener('mouseup', handleMouseUp);
    return () => {
      window.removeEventListener('mousemove', handleMouseMove);
      window.removeEventListener('mouseup', handleMouseUp);
    };
  }, [handleMouseMove, handleMouseUp]);

  // ── Scrubber position ─────────────────────────────────────────────────────
  const progress = duration > 0 ? (draggedTime / duration) * 100 : 0;

  return (
    <div className="relative py-3 select-none">

      {/* Comment tick marks */}
      <div className="absolute inset-x-0 top-1/2 -translate-y-1/2 h-0 pointer-events-none">
        {comments.map(comment => {
          if (comment.timestamp == null) return null;
          const pos = duration > 0 ? ((comment.timestamp) / duration) * 100 : 0;
          return (
            <button
              key={comment.id}
              className="absolute top-1/2 -translate-y-1/2 w-0.5 h-3 rounded-full transition-transform hover:h-4"
              style={{
                left: `${pos}%`,
                backgroundColor: comment.resolveStatus === 'RESOLVED' ? '#22c55e' : '#818CF8',
                pointerEvents: 'auto',
              }}
              onClick={(e) => {
                e.stopPropagation();
                onCommentClick(comment);
              }}
              title={`${comment.user?.name ?? 'Unknown'}: ${comment.content.slice(0, 60)}`}
            />
          );
        })}
      </div>

      {/* ── Seek bar ──────────────────────────────────────────────────── */}
      <div
        ref={trackRef}
        className="relative h-2 md:h-1.5 bg-white/10 rounded-full cursor-pointer"
        onMouseDown={handleMouseDown}
        onTouchStart={handleTouchStart}
        onTouchMove={handleTouchMove}
        onTouchEnd={handleTouchEnd}
        style={{ touchAction: 'none' }}
      >
        {/* Played / scrubbed portion */}
        <div
          className="absolute left-0 top-0 h-full bg-indigo-500 rounded-full will-change-width"
          style={{ width: `${progress}%` }}
        />

        {/* Scrubber — active state: indigo glow + scale up */}
        <div
          className="absolute top-1/2 -translate-y-1/2 rounded-full will-change-transform"
          style={{
            left: `calc(${progress}% - 8px)`,
            width: isDragging ? '18px' : '14px',
            height: isDragging ? '18px' : '14px',
            marginLeft: isDragging ? '-2px' : '0px',
            marginTop: isDragging ? '-2px' : '0px',
            background: 'white',
            border: '2px solid #818CF8',
            boxShadow: isDragging
              ? '0 0 0 4px rgba(99,102,241,0.25), 0 0 12px rgba(99,102,241,0.4)'
              : '0 1px 4px rgba(0,0,0,0.3)',
            transition: isDragging ? 'none' : 'width 0.12s, height 0.12s, margin 0.12s, box-shadow 0.12s',
          }}
        />
      </div>

      {/* ── Timecode tooltip — appears above scrubber during drag ───────── */}
      {isDragging && (
        <div
          className="absolute bottom-full mb-2 px-2 py-1 rounded-lg text-xs font-mono pointer-events-none whitespace-nowrap z-10"
          style={{
            left: `clamp(40px, ${tooltipX}%, calc(100% - 40px))`,
            transform: 'translateX(-50%)',
            background: 'rgba(10,11,20,0.95)',
            border: '1px solid rgba(99,102,241,0.40)',
            color: '#A5B4FC',
            backdropFilter: 'blur(8px)',
          }}
        >
          {formatTimecode(draggedTime, fps, duration)}
          {/* Tooltip pointer — points down to scrubber */}
          <div
            style={{
              position: 'absolute',
              top: '100%',
              left: '50%',
              transform: 'translateX(-50%)',
              width: 0,
              height: 0,
              borderLeft: '5px solid transparent',
              borderRight: '5px solid transparent',
              borderTop: '5px solid rgba(99,102,241,0.40)',
            }}
          />
        </div>
      )}

      {/* Timecode display */}
      <div className="flex justify-between mt-1.5 text-xs text-gray-400 font-mono">
        <span>{formatTimecode(draggedTime, fps, duration)}</span>
        <span>{formatTimecode(duration, fps, duration)}</span>
      </div>
    </div>
  );
}
