import React, { useRef, useState } from 'react';
import type { PageRef } from '../pdf/pdfTypes';
import CopyPagesDialog from './PageWorkspace/CopyPagesDialog';
import PageGrid from './PageWorkspace/PageGrid';
import PageSelectionToolbar from './PageWorkspace/PageSelectionToolbar';

interface ReorderPanelProps {
  pages: PageRef[];
  thumbnails: Record<string, string>;
  isBusy: boolean;
  hasPdf: boolean;
  selectedPageIds: string[];

  onRotateClockwise: (pageId: string) => void;
  onRotateCounterclockwise: (pageId: string) => void;
  onDelete: (pageId: string) => void;
  onReorder: (newPages: PageRef[]) => void;
  onCopyPagesToSlot: (pageIds: string[], insertSlot: number) => void;

  onToggleSelect: (
    pageId: string,
    visualIndex: number,
    e: React.MouseEvent<HTMLButtonElement>
  ) => void;
  onSelectAll: () => void;

  onOpenPreview: (pageId: string) => void;
  onClearSelection: () => void;
  onDeleteSelected: () => void;
}

const ReorderPanel: React.FC<ReorderPanelProps> = ({
  pages,
  thumbnails,
  isBusy,
  hasPdf,
  selectedPageIds,
  onRotateClockwise,
  onRotateCounterclockwise,
  onDelete,
  onReorder,
  onCopyPagesToSlot,
  onToggleSelect,
  onSelectAll,
  onOpenPreview,
  onClearSelection,
  onDeleteSelected,
}) => {
  const [draggingIndex, setDraggingIndex] = useState<number | null>(null);
  const [dropIndex, setDropIndex] = useState<number | null>(null);

  const [isCopyDragging, setIsCopyDragging] = useState(false);
  const [copyDialogOpen, setCopyDialogOpen] = useState(false);
  const [copyTargetPosition, setCopyTargetPosition] = useState('');
  const [copyDialogError, setCopyDialogError] = useState<string | null>(null);

  const dragGhostRef = useRef<HTMLDivElement | null>(null);

  const cleanupDragGhost = () => {
    if (dragGhostRef.current && dragGhostRef.current.parentNode) {
      dragGhostRef.current.parentNode.removeChild(dragGhostRef.current);
    }
    dragGhostRef.current = null;
  };

  const isCopyModifierPressed = (e: React.DragEvent) => {
    return e.ctrlKey || e.metaKey;
  };

  const getDraggedPages = (visualIndex: number): PageRef[] => {
    const draggedPage = pages[visualIndex];
    if (!draggedPage) return [];

    const selectedInVisualOrder = pages.filter((page) =>
      selectedPageIds.includes(page.id)
    );

    const draggingIsSelected =
      selectedInVisualOrder.length > 0 &&
      selectedInVisualOrder.some((page) => page.id === draggedPage.id);

    return draggingIsSelected ? selectedInVisualOrder : [draggedPage];
  };

  const createDragGhost = (e: React.DragEvent, count: number) => {
    cleanupDragGhost();

    const ghost = document.createElement('div');
    ghost.textContent = count === 1 ? '1 page' : `${count} pages`;

    ghost.style.position = 'fixed';
    ghost.style.top = '0';
    ghost.style.left = '0';
    ghost.style.padding = '4px 8px';
    ghost.style.borderRadius = '999px';
    ghost.style.background = '#111827';
    ghost.style.color = '#e5e7eb';
    ghost.style.fontSize = '12px';
    ghost.style.fontFamily =
      'system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif';
    ghost.style.zIndex = '9999';

    document.body.appendChild(ghost);
    dragGhostRef.current = ghost;

    const rect = ghost.getBoundingClientRect();
    e.dataTransfer.setDragImage(ghost, rect.width / 2, rect.height / 2);
  };

  const resetDragState = () => {
    cleanupDragGhost();
    setDraggingIndex(null);
    setDropIndex(null);
    setIsCopyDragging(false);
  };

  const handleDragStart = (visualIndex: number) => (e: React.DragEvent) => {
    setDraggingIndex(visualIndex);
    setDropIndex(visualIndex);

    const copying = isCopyModifierPressed(e);
    setIsCopyDragging(copying);

    e.dataTransfer.effectAllowed = 'copyMove';
    e.dataTransfer.dropEffect = copying ? 'copy' : 'move';
    e.dataTransfer.setData('text/plain', String(visualIndex));

    const draggedPages = getDraggedPages(visualIndex);
    createDragGhost(e, draggedPages.length);
  };

  const handleDragEnd = () => {
    resetDragState();
  };

  const handleCardDragOver = (visualIndex: number) => (e: React.DragEvent) => {
    if (draggingIndex == null) return;

    e.preventDefault();

    const copying = isCopyModifierPressed(e);
    setIsCopyDragging(copying);

    e.dataTransfer.dropEffect = copying ? 'copy' : 'move';

    const rect = (e.currentTarget as HTMLDivElement).getBoundingClientRect();
    const x = e.clientX - rect.left;

    const slot = x < rect.width / 2 ? visualIndex : visualIndex + 1;
    setDropIndex(slot);
  };

  const handleEndSlotDragOver = (e: React.DragEvent) => {
    if (draggingIndex == null) return;

    e.preventDefault();

    const copying = isCopyModifierPressed(e);
    setIsCopyDragging(copying);

    e.dataTransfer.dropEffect = copying ? 'copy' : 'move';

    setDropIndex(pages.length);
  };

  const handleDrop = (e: React.DragEvent) => {
    e.preventDefault();
    cleanupDragGhost();

    if (draggingIndex == null || dropIndex == null) return;

    const draggedPages = getDraggedPages(draggingIndex);
    if (draggedPages.length === 0) return;

    const shouldCopy = isCopyModifierPressed(e) || isCopyDragging;

    if (shouldCopy) {
      onCopyPagesToSlot(
        draggedPages.map((page) => page.id),
        dropIndex
      );

      setDraggingIndex(null);
      setDropIndex(null);
      setIsCopyDragging(false);
      return;
    }

    const indexMap = new Map<string, number>();
    pages.forEach((page, idx) => indexMap.set(page.id, idx));

    const countBefore = draggedPages.reduce((count, page) => {
      const idx = indexMap.get(page.id);
      if (idx != null && idx < dropIndex) return count + 1;
      return count;
    }, 0);

    const adjustedSlot = dropIndex - countBefore;
    const movingSet = new Set(draggedPages.map((page) => page.id));
    const remaining = pages.filter((page) => !movingSet.has(page.id));

    const newPages = [
      ...remaining.slice(0, adjustedSlot),
      ...draggedPages,
      ...remaining.slice(adjustedSlot),
    ];

    onReorder(newPages);

    setDraggingIndex(null);
    setDropIndex(null);
    setIsCopyDragging(false);
  };

  const handleDeleteClick = (pageId: string) => {
    onDelete(pageId);
    setDraggingIndex(null);
    setDropIndex(null);
  };

  const handleCheckboxClick =
    (pageId: string, visualIndex: number) =>
    (e: React.MouseEvent<HTMLButtonElement>) => {
      e.stopPropagation();
      onToggleSelect(pageId, visualIndex, e);
    };

  const handleCopySelectedClick = () => {
    if (selectedPageIds.length === 0) return;

    setCopyTargetPosition(String(pages.length + 1));
    setCopyDialogError(null);
    setCopyDialogOpen(true);
  };

  const handleCopyDialogCancel = () => {
    setCopyDialogOpen(false);
    setCopyDialogError(null);
  };

  const handleCopyTargetPositionChange = (value: string) => {
    setCopyTargetPosition(value);
    setCopyDialogError(null);
  };

  const handleCopyDialogConfirm = (e?: React.FormEvent) => {
    e?.preventDefault();

    if (selectedPageIds.length === 0) {
      setCopyDialogError('No pages selected.');
      return;
    }

    const maxPosition = pages.length + 1;
    const parsed = Number.parseInt(copyTargetPosition.trim(), 10);

    if (!Number.isFinite(parsed) || parsed < 1 || parsed > maxPosition) {
      setCopyDialogError(`Please enter a number between 1 and ${maxPosition}.`);
      return;
    }

    onCopyPagesToSlot(selectedPageIds, parsed - 1);

    setCopyDialogOpen(false);
    setCopyDialogError(null);
  };

  if (!hasPdf) {
    return (
      <div className="card">
        <h2>Pages</h2>
        <p>Open a PDF file to reorder, rotate, or delete its pages.</p>
      </div>
    );
  }

  const draggingPage = draggingIndex != null ? pages[draggingIndex] : null;
  const draggingSelectionActive =
    draggingPage != null &&
    selectedPageIds.length > 0 &&
    selectedPageIds.includes(draggingPage.id);
  const dropIndicatorColor = isCopyDragging ? '#16a34a' : '#2563eb';

  return (
    <>
      <div className="card">
        <h2>Pages</h2>
        <p style={{ fontSize: '0.85rem', color: '#6b7280' }}>
          Tap/click a page to preview it. Use the checkbox to select pages
          (Shift for ranges). Drag to reorder; dragging a selected page moves
          the whole selection. Hold Ctrl/⌘ while dropping to copy instead of
          move. Shortcuts: Ctrl/⌘+A selects all, Delete removes selected pages,
          Esc clears selection.
        </p>

        <PageSelectionToolbar
          selectedCount={selectedPageIds.length}
          onCopySelected={handleCopySelectedClick}
          onDeleteSelected={onDeleteSelected}
          onSelectAll={onSelectAll}
          onClearSelection={onClearSelection}
        />

        <PageGrid
          pages={pages}
          thumbnails={thumbnails}
          selectedPageIds={selectedPageIds}
          isBusy={isBusy}
          draggingIndex={draggingIndex}
          dropIndex={dropIndex}
          draggingSelectionActive={draggingSelectionActive}
          isCopyDragging={isCopyDragging}
          dropIndicatorColor={dropIndicatorColor}
          onDragStart={handleDragStart}
          onDragEnd={handleDragEnd}
          onCardDragOver={handleCardDragOver}
          onEndSlotDragOver={handleEndSlotDragOver}
          onDrop={handleDrop}
          onOpenPreview={onOpenPreview}
          onToggleSelect={handleCheckboxClick}
          onRotateClockwise={onRotateClockwise}
          onRotateCounterclockwise={onRotateCounterclockwise}
          onDelete={handleDeleteClick}
        />
      </div>

      {copyDialogOpen && (
        <CopyPagesDialog
          selectedCount={selectedPageIds.length}
          pageCount={pages.length}
          targetPosition={copyTargetPosition}
          error={copyDialogError}
          onTargetPositionChange={handleCopyTargetPositionChange}
          onCancel={handleCopyDialogCancel}
          onConfirm={handleCopyDialogConfirm}
        />
      )}
    </>
  );
};

export default ReorderPanel;
