import { useCallback, useEffect, useRef, useState } from 'react';
import type { HistoryEntry, EventSnapshot } from '@/components/timeline/history-types';

type EventType = 'milestone' | 'checkpoint' | 'activity';
type UpdateInput = {
  id: string;
  date?: number;
  endDate?: number | null;
  isCompleted?: number;
  title?: string;
  type?: EventType;
};
type DeleteInput = { id: string };
type CreateInput = {
  id?: string;
  projectId?: string;
  title: string;
  date: number;
  endDate?: number;
  type?: EventType;
  isCompleted?: number;
  isAiSuggested?: number;
};

export function useTimelineHistory({ disabled = false }: { disabled?: boolean } = {}) {
  const historyOpRef = useRef(false);
  const pendingCreatePayloadRef = useRef<EventSnapshot | null>(null);
  const [undoStack, setUndoStack] = useState<HistoryEntry[]>([]);
  const [redoStack, setRedoStack] = useState<HistoryEntry[]>([]);

  // Stable refs the caller populates with latest mutation functions each render
  // eslint-disable-next-line @typescript-eslint/no-empty-function
  const updateMutateRef = useRef<(input: UpdateInput) => void>(() => {});
  // eslint-disable-next-line @typescript-eslint/no-empty-function
  const deleteMutateRef = useRef<(input: DeleteInput) => void>(() => {});
  // eslint-disable-next-line @typescript-eslint/no-empty-function
  const createMutateRef = useRef<(input: CreateInput) => void>(() => {});

  function clearHistory() {
    setUndoStack([]);
    setRedoStack([]);
  }

  function record(entry: HistoryEntry) {
    setUndoStack((prev) => {
      const next = [...prev, entry];
      return next.length > 50 ? next.slice(1) : next;
    });
    setRedoStack([]);
  }

  const undo = useCallback(() => {
    const entry = undoStack.at(-1);
    if (!entry) return;
    setUndoStack((prev) => prev.slice(0, -1));
    setRedoStack((prev) => [...prev, entry]);
    historyOpRef.current = true;
    if (entry.kind === 'update') {
      updateMutateRef.current({ id: entry.id, ...entry.prev });
    } else if (entry.kind === 'create') {
      deleteMutateRef.current({ id: entry.id });
    } else {
      createMutateRef.current({
        id: entry.snapshot.id,
        projectId: entry.snapshot.projectId ?? undefined,
        title: entry.snapshot.title,
        date: entry.snapshot.date,
        endDate: entry.snapshot.endDate ?? undefined,
        type: entry.snapshot.type,
        isCompleted: entry.snapshot.isCompleted,
        isAiSuggested: entry.snapshot.isAiSuggested,
      });
    }
  }, [undoStack]);

  const redo = useCallback(() => {
    const entry = redoStack.at(-1);
    if (!entry) return;
    setRedoStack((prev) => prev.slice(0, -1));
    setUndoStack((prev) => [...prev, entry]);
    historyOpRef.current = true;
    if (entry.kind === 'update') {
      updateMutateRef.current({ id: entry.id, ...entry.next });
    } else if (entry.kind === 'create') {
      createMutateRef.current({
        id: entry.payload.id,
        projectId: entry.payload.projectId ?? undefined,
        title: entry.payload.title,
        date: entry.payload.date,
        endDate: entry.payload.endDate ?? undefined,
        type: entry.payload.type,
        isCompleted: entry.payload.isCompleted,
        isAiSuggested: entry.payload.isAiSuggested,
      });
    } else {
      deleteMutateRef.current({ id: entry.id });
    }
  }, [redoStack]);

  // Latest-ref pattern so the keyboard listener always calls the current undo/redo
  const undoRef = useRef(undo);
  undoRef.current = undo;
  const redoRef = useRef(redo);
  redoRef.current = redo;

  useEffect(() => {
    function onKeyDown(e: KeyboardEvent) {
      if (!(e.ctrlKey || e.metaKey) || disabled) return;
      const active = document.activeElement;
      const inInput =
        active instanceof HTMLElement &&
        (active.tagName === 'INPUT' || active.tagName === 'TEXTAREA' || active.isContentEditable);
      if (inInput) return;
      if (e.key === 'z' && !e.shiftKey) {
        e.preventDefault();
        undoRef.current();
      } else if (e.key === 'y' || (e.key === 'z' && e.shiftKey)) {
        e.preventDefault();
        redoRef.current();
      }
    }
    window.addEventListener('keydown', onKeyDown);
    return () => window.removeEventListener('keydown', onKeyDown);
  }, [disabled]);

  return {
    historyOpRef,
    pendingCreatePayloadRef,
    record,
    undo,
    redo,
    canUndo: undoStack.length > 0,
    canRedo: redoStack.length > 0,
    clearHistory,
    updateMutateRef,
    deleteMutateRef,
    createMutateRef,
  };
}
