import { useState, useRef, useCallback } from 'react';
import type { VideoSegmentMetadata, PausePointData } from '../../types/api';
import { PausePointEditor } from './PausePointEditor';

interface ContextMenuState {
  x: number;
  y: number;
  timeMs: number;
  nearPausePoint: PausePointData | null;
}

interface TimelinePreviewProps {
  segments: VideoSegmentMetadata[];
  pausePoints: PausePointData[];
  totalDurationMs: number;
  currentTimeMs: number;
  onSegmentClick: (segment: VideoSegmentMetadata) => void;
  onPausePointClick: (pausePoint: PausePointData) => void;
  onPausePointUpdate: (cueIndex: number, adjustedMs: number) => void;
  onRegenerateTTS: (cueIndex: number) => void;
  regenerationQueue: number[];
  isStale?: boolean;
  onPausePointAdd?: (timeMs: number) => void;  // right-click → add pause at position
}

export function TimelinePreview({
  segments,
  pausePoints,
  totalDurationMs,
  currentTimeMs,
  onSegmentClick,
  onPausePointClick,
  onPausePointUpdate,
  onRegenerateTTS,
  regenerationQueue,
  isStale = false,
  onPausePointAdd,
}: TimelinePreviewProps) {
  const [selectedPausePoint, setSelectedPausePoint] = useState<PausePointData | null>(null);
  const [editorPosition, setEditorPosition] = useState({ x: 0, y: 0 });
  const [contextMenu, setContextMenu] = useState<ContextMenuState | null>(null);
  const timelineRef = useRef<HTMLDivElement>(null);

  // ── Drag state (B1 marker drag, B2 freeze-block drag) ─────────────────────
  // State drives rendering (tooltip, cursor, position); refs allow event handlers
  // to read current values synchronously without waiting for a React re-render
  // (pointer events can fire faster than React batches state commits).
  const [draggingCueIndex, setDraggingCueIndex] = useState<number | null>(null);
  const [dragMs, setDragMs] = useState<number | null>(null);
  const draggingCueIndexRef = useRef<number | null>(null);
  const dragMsRef = useRef<number | null>(null);
  const dragStartXRef = useRef<number>(0);
  const movedRef = useRef<boolean>(false);

  const getPositionPercent = useCallback(
    (ms: number) => (totalDurationMs > 0 ? (ms / totalDurationMs) * 100 : 0),
    [totalDurationMs]
  );

  // Converts a clientX coordinate to a clamped ms value for the given pause point.
  const clientXToMs = useCallback(
    (clientX: number, pp: PausePointData): number => {
      if (!timelineRef.current || totalDurationMs <= 0) return pp.adjusted_ms ?? pp.original_ms;
      const rect = timelineRef.current.getBoundingClientRect();
      const fraction = Math.max(0, Math.min(1, (clientX - rect.left) / rect.width));
      const raw = Math.round(fraction * totalDurationMs);
      return Math.max(pp.min_bound_ms, Math.min(pp.max_bound_ms, raw));
    },
    [totalDurationMs]
  );

  // ── Pointer handlers wired to each pause-point marker / freeze block ───────

  const handleDragPointerDown = (e: React.PointerEvent, pp: PausePointData) => {
    if (e.button !== 0) return; // left-button only; let right-click fall through to onContextMenu
    e.stopPropagation();
    (e.currentTarget as HTMLElement).setPointerCapture(e.pointerId);
    dragStartXRef.current = e.clientX;
    movedRef.current = false;
    const initialMs = pp.adjusted_ms ?? pp.original_ms;
    draggingCueIndexRef.current = pp.cue_index;
    dragMsRef.current = initialMs;
    setDraggingCueIndex(pp.cue_index);
    setDragMs(initialMs);
  };

  const handleDragPointerMove = (e: React.PointerEvent, pp: PausePointData) => {
    if (draggingCueIndexRef.current !== pp.cue_index) return;
    if (Math.abs(e.clientX - dragStartXRef.current) > 3) movedRef.current = true;
    if (!movedRef.current) return;
    const ms = clientXToMs(e.clientX, pp);
    dragMsRef.current = ms;
    setDragMs(ms);
  };

  const handleDragPointerUp = (
    e: React.PointerEvent,
    pp: PausePointData,
    openEditorFn: () => void
  ) => {
    if (draggingCueIndexRef.current !== pp.cue_index) return;
    (e.currentTarget as HTMLElement).releasePointerCapture(e.pointerId);
    const didMove = movedRef.current;
    const finalMs = dragMsRef.current;
    draggingCueIndexRef.current = null;
    dragMsRef.current = null;
    setDraggingCueIndex(null);
    setDragMs(null);

    if (didMove && finalMs !== null && finalMs !== (pp.adjusted_ms ?? pp.original_ms)) {
      onPausePointUpdate(pp.cue_index, finalMs);
    } else if (!didMove) {
      openEditorFn();
    }
  };

  // ── Existing click / editor handlers ──────────────────────────────────────

  const handlePausePointMarkerClick = (
    e: React.MouseEvent | React.PointerEvent,
    pausePoint: PausePointData
  ) => {
    e.stopPropagation();
    const rect = (e.target as HTMLElement).getBoundingClientRect();
    setEditorPosition({ x: rect.left, y: rect.bottom + 8 });
    setSelectedPausePoint(pausePoint);
    onPausePointClick(pausePoint);
  };

  const handleSegmentClick = (segment: VideoSegmentMetadata) => {
    onSegmentClick(segment);
    if (segment.is_freeze_frame && segment.cue_index !== null) {
      const pausePoint = pausePoints.find(pp => pp.cue_index === segment.cue_index);
      if (pausePoint) {
        onPausePointClick(pausePoint);
      }
    }
  };

  const handleEditorSave = (adjustedMs: number) => {
    if (selectedPausePoint) {
      onPausePointUpdate(selectedPausePoint.cue_index, adjustedMs);
      setSelectedPausePoint(null);
    }
  };

  const handleEditorClose = () => {
    setSelectedPausePoint(null);
  };

  const handleContextMenu = (e: React.MouseEvent) => {
    e.preventDefault();
    if (!timelineRef.current || totalDurationMs <= 0) return;
    const rect = timelineRef.current.getBoundingClientRect();
    const fraction = Math.max(0, Math.min(1, (e.clientX - rect.left) / rect.width));
    const timeMs = Math.round(fraction * totalDurationMs);
    // Find if click is within 1.5% of a pause point
    const threshold = totalDurationMs * 0.015;
    const near = pausePoints.find(pp => {
      const ppMs = pp.adjusted_ms ?? pp.original_ms;
      return Math.abs(ppMs - timeMs) <= threshold;
    }) ?? null;
    setContextMenu({ x: e.clientX, y: e.clientY, timeMs, nearPausePoint: near });
    setSelectedPausePoint(null);
  };

  const closeContextMenu = () => setContextMenu(null);

  const handleContextMenuPauseOpen = (pp: PausePointData) => {
    setEditorPosition({ x: contextMenu!.x, y: contextMenu!.y + 8 });
    setSelectedPausePoint(pp);
    onPausePointClick(pp);
    setContextMenu(null);
  };

  const formatTime = (ms: number) => {
    const totalSeconds = Math.floor(ms / 1000);
    const minutes = Math.floor(totalSeconds / 60);
    const seconds = totalSeconds % 60;
    const milliseconds = Math.floor(ms % 1000);
    return `${minutes}:${seconds.toString().padStart(2, '0')}.${milliseconds.toString().padStart(3, '0')}`;
  };

  return (
    <div className="relative">
      {/* Staleness warning */}
      {isStale && (
        <div className="mb-1 px-2 py-1 bg-amber-50 border border-amber-300 rounded text-xs text-amber-700">
          Timeline preview may be outdated — re-render to see latest changes
        </div>
      )}
      {/* Timeline container */}
      <div
        ref={timelineRef}
        className={`relative h-16 rounded-lg overflow-hidden ${isStale ? 'bg-amber-50' : 'bg-gray-100'}`}
        onContextMenu={handleContextMenu}
      >
        {/* Segments */}
        {segments.map((segment) => {
          // During drag of this segment's cue, offset the block visually by the drag delta
          const linkedPP = segment.is_freeze_frame && segment.cue_index !== null
            ? pausePoints.find(pp => pp.cue_index === segment.cue_index) ?? null
            : null;
          const isDraggingBlock = linkedPP !== null && draggingCueIndex === linkedPP.cue_index;

          let leftMs = segment.start_ms;
          if (isDraggingBlock && dragMs !== null && linkedPP) {
            const origPpMs = linkedPP.adjusted_ms ?? linkedPP.original_ms;
            leftMs = segment.start_ms + (dragMs - origPpMs);
          }

          const leftPercent = getPositionPercent(leftMs);
          const widthPercent = getPositionPercent(segment.duration_ms);
          const isRegenerationQueued =
            segment.is_freeze_frame &&
            segment.cue_index !== null &&
            regenerationQueue.includes(segment.cue_index);

          return (
            <div
              key={segment.segment_index}
              className={`absolute top-0 h-full transition-all hover:opacity-90 ${
                segment.is_freeze_frame
                  ? isRegenerationQueued
                    ? 'bg-amber-400'
                    : isDraggingBlock
                      ? 'bg-orange-500 cursor-grabbing'
                      : 'bg-orange-400 cursor-grab'
                  : 'bg-blue-400 cursor-pointer'
              }`}
              style={{
                left: `${leftPercent}%`,
                width: `${Math.max(widthPercent, 0.5)}%`,
              }}
              onClick={() => {
                if (!movedRef.current) handleSegmentClick(segment);
              }}
              onPointerDown={linkedPP ? (e) => handleDragPointerDown(e, linkedPP) : undefined}
              onPointerMove={linkedPP ? (e) => handleDragPointerMove(e, linkedPP) : undefined}
              onPointerUp={linkedPP
                ? (e) => handleDragPointerUp(e, linkedPP, () => handleSegmentClick(segment))
                : undefined}
              title={
                segment.is_freeze_frame
                  ? `AD Cue ${segment.cue_index !== null ? segment.cue_index + 1 : ''}${isRegenerationQueued ? ' (Regenerate queued)' : ''} — drag to move`
                  : `Video segment ${segment.segment_index}`
              }
            >
              {/* Cue index label for freeze frames */}
              {segment.is_freeze_frame && segment.cue_index !== null && widthPercent > 2 && (
                <div className="absolute inset-0 flex items-center justify-center">
                  <span className="text-xs font-bold text-white drop-shadow">
                    {segment.cue_index !== null ? segment.cue_index + 1 : ''}
                  </span>
                </div>
              )}
            </div>
          );
        })}

        {/* Pause point markers */}
        {pausePoints.map((pausePoint) => {
          const isDraggingThis = draggingCueIndex === pausePoint.cue_index;
          const displayMs = isDraggingThis && dragMs !== null
            ? dragMs
            : (pausePoint.adjusted_ms ?? pausePoint.original_ms);
          const leftPercent = getPositionPercent(displayMs);
          const isAdjusted = pausePoint.adjusted_ms !== null;

          return (
            <div
              key={`pause-${pausePoint.cue_index}`}
              className={`absolute top-0 w-2 h-full z-10 transition-[width] select-none ${
                isDraggingThis
                  ? 'cursor-grabbing w-3 ' + (isAdjusted ? 'bg-purple-700' : 'bg-red-700')
                  : 'hover:w-3 ' + (isAdjusted ? 'bg-purple-600 cursor-grab' : 'bg-red-600 cursor-grab')
              }`}
              style={{ left: `${leftPercent}%` }}
              onPointerDown={(e) => handleDragPointerDown(e, pausePoint)}
              onPointerMove={(e) => handleDragPointerMove(e, pausePoint)}
              onPointerUp={(e) =>
                handleDragPointerUp(e, pausePoint, () =>
                  handlePausePointMarkerClick(e, pausePoint)
                )
              }
              onContextMenu={(e) => {
                e.preventDefault();
                e.stopPropagation();
                handleContextMenuPauseOpen(pausePoint);
              }}
              title={`Pause point ${pausePoint.cue_index + 1}: ${formatTime(pausePoint.adjusted_ms ?? pausePoint.original_ms)}${isAdjusted ? ' (adjusted)' : ''} — drag to move`}
            >
              {/* Drag time tooltip (B3) */}
              {isDraggingThis && dragMs !== null && (
                <div
                  className="absolute -top-7 left-1/2 -translate-x-1/2 bg-gray-800 text-white text-xs rounded px-1.5 py-0.5 whitespace-nowrap pointer-events-none shadow"
                >
                  {formatTime(dragMs)}
                </div>
              )}
            </div>
          );
        })}

        {/* Current time indicator */}
        <div
          className="absolute top-0 w-0.5 h-full bg-green-500 z-20 pointer-events-none"
          style={{ left: `${getPositionPercent(currentTimeMs)}%` }}
        />
      </div>

      {/* Time labels */}
      <div className="flex justify-between mt-1 text-xs text-gray-500">
        <span>0:00</span>
        <span>{formatTime(totalDurationMs)}</span>
      </div>

      {/* Legend */}
      <div className="flex gap-4 mt-2 text-xs">
        <div className="flex items-center gap-1">
          <div className="w-3 h-3 bg-blue-400 rounded" />
          <span>Video</span>
        </div>
        <div className="flex items-center gap-1">
          <div className="w-3 h-3 bg-orange-400 rounded" />
          <span>AD Audio (drag to move)</span>
        </div>
        <div className="flex items-center gap-1">
          <div className="w-3 h-3 bg-amber-400 rounded" />
          <span>Regenerate Queued</span>
        </div>
        <div className="flex items-center gap-1">
          <div className="w-1 h-3 bg-red-600" />
          <span>Pause Point (drag to move)</span>
        </div>
        <div className="flex items-center gap-1">
          <div className="w-1 h-3 bg-purple-600" />
          <span>Adjusted</span>
        </div>
      </div>

      {/* Pause point editor popover */}
      {selectedPausePoint && (
        <PausePointEditor
          pausePoint={selectedPausePoint}
          position={editorPosition}
          onSave={handleEditorSave}
          onCancel={handleEditorClose}
          onRegenerateTTS={() => {
            onRegenerateTTS(selectedPausePoint.cue_index);
            setSelectedPausePoint(null);
          }}
          isRegenerationQueued={regenerationQueue.includes(selectedPausePoint.cue_index)}
        />
      )}

      {/* Right-click context menu */}
      {contextMenu && (
        <>
          <div className="fixed inset-0 z-40" onClick={closeContextMenu} onContextMenu={(e) => { e.preventDefault(); closeContextMenu(); }} />
          <div
            className="fixed z-50 bg-white border border-gray-200 rounded-lg shadow-lg py-1 min-w-[200px] text-sm"
            style={{ left: contextMenu.x, top: contextMenu.y }}
          >
            <div className="px-3 py-1.5 text-xs text-gray-500 border-b border-gray-100">
              {formatTime(contextMenu.timeMs)}
            </div>
            {contextMenu.nearPausePoint ? (
              <>
                <button
                  className="w-full text-left px-3 py-2 hover:bg-gray-50 flex items-center gap-2"
                  onClick={() => handleContextMenuPauseOpen(contextMenu.nearPausePoint!)}
                >
                  ✏️ Edit pause point {contextMenu.nearPausePoint.cue_index + 1} timing
                </button>
                <button
                  className="w-full text-left px-3 py-2 hover:bg-gray-50 flex items-center gap-2"
                  onClick={() => { onRegenerateTTS(contextMenu.nearPausePoint!.cue_index); closeContextMenu(); }}
                >
                  🔄 Regenerate TTS for cue {contextMenu.nearPausePoint.cue_index + 1}
                </button>
              </>
            ) : onPausePointAdd ? (
              <button
                className="w-full text-left px-3 py-2 hover:bg-gray-50 flex items-center gap-2"
                onClick={() => { onPausePointAdd(contextMenu.timeMs); closeContextMenu(); }}
              >
                ➕ Add AD cue at {formatTime(contextMenu.timeMs)}
              </button>
            ) : (
              <div className="px-3 py-2 text-gray-400 text-xs">No pause point nearby</div>
            )}
          </div>
        </>
      )}
    </div>
  );
}
