import React, { useState, useCallback, useRef, useEffect, useMemo } from "react";
import {
  Button, Text, Center, Checkbox, Box, Tooltip, ActionIcon,
  Notification, TextInput, LoadingOverlay, Modal, Alert,
  Stack, Group
} from "@mantine/core";
import { useTranslation } from "react-i18next";
import { useFileContext, useCurrentFile } from "../../contexts/FileContext";
import { ViewType, ToolType } from "../../types/fileContext";
import { PDFDocument, PDFPage } from "../../types/pageEditor";
import { ProcessedFile as EnhancedProcessedFile } from "../../types/processing";
import { useUndoRedo } from "../../hooks/useUndoRedo";
import {
  RotatePagesCommand,
  DeletePagesCommand,
  ReorderPageCommand,
  MovePagesCommand,
  ToggleSplitCommand
} from "../../commands/pageCommands";
import { pdfExportService } from "../../services/pdfExportService";
import { useThumbnailGeneration } from "../../hooks/useThumbnailGeneration";
import { calculateScaleFromFileSize } from "../../utils/thumbnailUtils";
import { fileStorage } from "../../services/fileStorage";
import './PageEditor.module.css';
import PageThumbnail from './PageThumbnail';
import BulkSelectionPanel from './BulkSelectionPanel';
import DragDropGrid from './DragDropGrid';
import SkeletonLoader from '../shared/SkeletonLoader';
import NavigationWarningModal from '../shared/NavigationWarningModal';

export interface PageEditorProps {
  // Optional callbacks to expose internal functions for PageEditorControls
  onFunctionsReady?: (functions: {
    handleUndo: () => void;
    handleRedo: () => void;
    canUndo: boolean;
    canRedo: boolean;
    handleRotate: (direction: 'left' | 'right') => void;
    handleDelete: () => void;
    handleSplit: () => void;
    showExportPreview: (selectedOnly: boolean) => void;
    onExportSelected: () => void;
    onExportAll: () => void;
    exportLoading: boolean;
    selectionMode: boolean;
    selectedPages: number[];
    closePdf: () => void;
  }) => void;
}

const PageEditor = ({
  onFunctionsReady,
}: PageEditorProps) => {
  const { t } = useTranslation();

  // Get file context
  const fileContext = useFileContext();
  const { file: currentFile, processedFile: currentProcessedFile } = useCurrentFile();

  // Use file context state
  const {
    activeFiles,
    processedFiles,
    selectedPageNumbers,
    setSelectedPages,
    updateProcessedFile,
    setHasUnsavedChanges,
    hasUnsavedChanges,
    isProcessing: globalProcessing,
    processingProgress,
    clearAllFiles
  } = fileContext;

  // Edit state management
  const [editedDocument, setEditedDocument] = useState<PDFDocument | null>(null);
  const [hasUnsavedDraft, setHasUnsavedDraft] = useState(false);
  const [showResumeModal, setShowResumeModal] = useState(false);
  const [foundDraft, setFoundDraft] = useState<any>(null);
  const autoSaveTimer = useRef<NodeJS.Timeout | null>(null);

  // Simple computed document from processed files (no caching needed)
  const mergedPdfDocument = useMemo(() => {
    if (activeFiles.length === 0) return null;

    if (activeFiles.length === 1) {
      // Single file
      const processedFile = processedFiles.get(activeFiles[0]);
      if (!processedFile) return null;

      return {
        id: processedFile.id,
        name: activeFiles[0].name,
        file: activeFiles[0],
        pages: processedFile.pages.map(page => ({
          ...page,
          rotation: page.rotation || 0,
          splitBefore: page.splitBefore || false
        })),
        totalPages: processedFile.totalPages
      };
    } else {
      // Multiple files - merge them
      const allPages: PDFPage[] = [];
      let totalPages = 0;
      const filenames: string[] = [];

      activeFiles.forEach((file, i) => {
        const processedFile = processedFiles.get(file);
        if (processedFile) {
          filenames.push(file.name.replace(/\.pdf$/i, ''));

          processedFile.pages.forEach((page, pageIndex) => {
            const newPage: PDFPage = {
              ...page,
              id: `${i}-${page.id}`, // Unique ID across all files
              pageNumber: totalPages + pageIndex + 1,
              rotation: page.rotation || 0,
              splitBefore: page.splitBefore || false
            };
            allPages.push(newPage);
          });

          totalPages += processedFile.pages.length;
        }
      });

      if (allPages.length === 0) return null;

      return {
        id: `merged-${Date.now()}`,
        name: filenames.join(' + '),
        file: activeFiles[0], // Use first file as reference
        pages: allPages,
        totalPages: totalPages
      };
    }
  }, [activeFiles, processedFiles]);

  // Display document: Use edited version if exists, otherwise original
  const displayDocument = editedDocument || mergedPdfDocument;

  const [filename, setFilename] = useState<string>("");


  // Page editor state (use context for selectedPages)
  const [status, setStatus] = useState<string | null>(null);
  const [csvInput, setCsvInput] = useState<string>("");
  const [selectionMode, setSelectionMode] = useState(false);

  // Drag and drop state
  const [draggedPage, setDraggedPage] = useState<number | null>(null);
  const [dropTarget, setDropTarget] = useState<number | 'end' | null>(null);
  const [multiPageDrag, setMultiPageDrag] = useState<{pageNumbers: number[], count: number} | null>(null);
  const [dragPosition, setDragPosition] = useState<{x: number, y: number} | null>(null);

  // Export state
  const [exportLoading, setExportLoading] = useState(false);
  const [showExportModal, setShowExportModal] = useState(false);
  const [exportPreview, setExportPreview] = useState<{pageCount: number; splitCount: number; estimatedSize: string} | null>(null);

  // Animation state
  const [movingPage, setMovingPage] = useState<number | null>(null);
  const [pagePositions, setPagePositions] = useState<Map<string, { x: number; y: number }>>(new Map());
  const [isAnimating, setIsAnimating] = useState(false);
  const pageRefs = useRef<Map<string, HTMLDivElement>>(new Map());
  const fileInputRef = useRef<() => void>(null);

  // Undo/Redo system
  const { executeCommand, undo, redo, canUndo, canRedo } = useUndoRedo();

  // Set initial filename when document changes
  useEffect(() => {
    if (mergedPdfDocument) {
      if (activeFiles.length === 1) {
        setFilename(activeFiles[0].name.replace(/\.pdf$/i, ''));
      } else {
        const filenames = activeFiles.map(f => f.name.replace(/\.pdf$/i, ''));
        setFilename(filenames.join('_'));
      }
    }
  }, [mergedPdfDocument, activeFiles]);

  // Handle file upload from FileUploadSelector (now using context)
  const handleMultipleFileUpload = useCallback(async (uploadedFiles: File[]) => {
    if (!uploadedFiles || uploadedFiles.length === 0) {
      setStatus('No files provided');
      return;
    }

    // Add files to context
    await fileContext.addFiles(uploadedFiles);
    setStatus(`Added ${uploadedFiles.length} file(s) for processing`);
  }, [fileContext]);


  // PageEditor no longer handles cleanup - it's centralized in FileContext

  // Shared PDF instance for thumbnail generation
  const [sharedPdfInstance, setSharedPdfInstance] = useState<any>(null);
  const [thumbnailGenerationStarted, setThumbnailGenerationStarted] = useState(false);

  // Thumbnail generation (opt-in for visual tools)
  const {
    generateThumbnails,
    addThumbnailToCache,
    getThumbnailFromCache,
    stopGeneration,
    destroyThumbnails
  } = useThumbnailGeneration();

  // Start thumbnail generation process (separate from document loading)
  const startThumbnailGeneration = useCallback(() => {
    console.log('🎬 PageEditor: startThumbnailGeneration called');
    console.log('🎬 Conditions - mergedPdfDocument:', !!mergedPdfDocument, 'activeFiles:', activeFiles.length, 'started:', thumbnailGenerationStarted);

    if (!mergedPdfDocument || activeFiles.length !== 1 || thumbnailGenerationStarted) {
      console.log('🎬 PageEditor: Skipping thumbnail generation due to conditions');
      return;
    }

    const file = activeFiles[0];
    const totalPages = mergedPdfDocument.totalPages;

    console.log('🎬 PageEditor: Starting thumbnail generation for', totalPages, 'pages');
    setThumbnailGenerationStarted(true);

    // Run everything asynchronously to avoid blocking the main thread
    setTimeout(async () => {
      try {
        // Load PDF array buffer for Web Workers
        const arrayBuffer = await file.arrayBuffer();

        // Generate page numbers for pages that don't have thumbnails yet
        const pageNumbers = Array.from({ length: totalPages }, (_, i) => i + 1)
          .filter(pageNum => {
            const page = mergedPdfDocument.pages.find(p => p.pageNumber === pageNum);
            return !page?.thumbnail; // Only generate for pages without thumbnails
          });

        console.log(`🎬 PageEditor: Generating thumbnails for ${pageNumbers.length} pages (out of ${totalPages} total):`, pageNumbers.slice(0, 10), pageNumbers.length > 10 ? '...' : '');

        // If no pages need thumbnails, we're done
        if (pageNumbers.length === 0) {
          console.log('🎬 PageEditor: All pages already have thumbnails, no generation needed');
          return;
        }

        // Calculate quality scale based on file size
        const scale = activeFiles.length === 1 ? calculateScaleFromFileSize(activeFiles[0].size) : 0.2;

        // Start parallel thumbnail generation WITHOUT blocking the main thread
        const generationPromise = generateThumbnails(
          arrayBuffer,
          pageNumbers,
          {
            scale, // Dynamic quality based on file size
            quality: 0.8,
            batchSize: 15, // Smaller batches per worker for smoother UI
            parallelBatches: 3 // Use 3 Web Workers in parallel
          },
          // Progress callback (throttled for better performance)
          (progress) => {
            console.log(`🎬 PageEditor: Progress - ${progress.completed}/${progress.total} pages, ${progress.thumbnails.length} new thumbnails`);
            // Batch process thumbnails to reduce main thread work
            requestAnimationFrame(() => {
              progress.thumbnails.forEach(({ pageNumber, thumbnail }) => {
                // Check cache first, then send thumbnail
                const pageId = `${file.name}-page-${pageNumber}`;
                const cached = getThumbnailFromCache(pageId);

                if (!cached) {
                  // Cache and send to component
                  addThumbnailToCache(pageId, thumbnail);

                  window.dispatchEvent(new CustomEvent('thumbnailReady', {
                    detail: { pageNumber, thumbnail, pageId }
                  }));
                  console.log(`✓ PageEditor: Dispatched thumbnail for page ${pageNumber}`);
                }
              });
            });
          }
        );

        // Handle completion properly
        generationPromise
          .then((allThumbnails) => {
            console.log(`✅ PageEditor: Thumbnail generation completed! Generated ${allThumbnails.length} thumbnails`);
            // Don't reset thumbnailGenerationStarted here - let it stay true to prevent restarts
          })
          .catch(error => {
            console.error('✗ PageEditor: Web Worker thumbnail generation failed:', error);
            setThumbnailGenerationStarted(false);
          });

      } catch (error) {
        console.error('Failed to start Web Worker thumbnail generation:', error);
        setThumbnailGenerationStarted(false);
      }
    }, 0); // setTimeout with 0ms to defer to next tick
  }, [mergedPdfDocument, activeFiles, thumbnailGenerationStarted, getThumbnailFromCache, addThumbnailToCache]);

  // Start thumbnail generation after document loads
  useEffect(() => {
    console.log('🎬 PageEditor: Thumbnail generation effect triggered');
    console.log('🎬 Conditions - mergedPdfDocument:', !!mergedPdfDocument, 'started:', thumbnailGenerationStarted);

    if (mergedPdfDocument && !thumbnailGenerationStarted) {
      // Check if ALL pages already have thumbnails from processed files
      const totalPages = mergedPdfDocument.pages.length;
      const pagesWithThumbnails = mergedPdfDocument.pages.filter(page => page.thumbnail).length;
      const hasAllThumbnails = pagesWithThumbnails === totalPages;

      console.log('🎬 PageEditor: Thumbnail status:', {
        totalPages,
        pagesWithThumbnails,
        hasAllThumbnails,
        missingThumbnails: totalPages - pagesWithThumbnails
      });

      if (hasAllThumbnails) {
        console.log('🎬 PageEditor: Skipping generation - all thumbnails already exist');
        return; // Skip generation if ALL thumbnails already exist
      }

      console.log('🎬 PageEditor: Some thumbnails missing, proceeding with generation');
      // Small delay to let document render, then start thumbnail generation
      console.log('🎬 PageEditor: Scheduling thumbnail generation in 500ms');
      const timer = setTimeout(startThumbnailGeneration, 500);
      return () => clearTimeout(timer);
    }
  }, [mergedPdfDocument, startThumbnailGeneration, thumbnailGenerationStarted]);

  // Cleanup shared PDF instance when component unmounts (but preserve cache)
  useEffect(() => {
    return () => {
      if (sharedPdfInstance) {
        sharedPdfInstance.destroy();
        setSharedPdfInstance(null);
      }
      setThumbnailGenerationStarted(false);
      // DON'T stop generation on file changes - preserve cache for view switching
      // stopGeneration();
    };
  }, [sharedPdfInstance]); // Only depend on PDF instance, not activeFiles

  // Clear selections when files change
  useEffect(() => {
    setSelectedPages([]);
    setCsvInput("");
    setSelectionMode(false);
  }, [activeFiles, setSelectedPages]);

  // Sync csvInput with selectedPageNumbers changes
  useEffect(() => {
    // Simply sort the page numbers and join them
    const sortedPageNumbers = [...selectedPageNumbers].sort((a, b) => a - b);
    const newCsvInput = sortedPageNumbers.join(', ');
    setCsvInput(newCsvInput);
  }, [selectedPageNumbers]);

  useEffect(() => {
    const handleGlobalDragEnd = () => {
      // Clean up drag state when drag operation ends anywhere
      setDraggedPage(null);
      setDropTarget(null);
      setMultiPageDrag(null);
      setDragPosition(null);
    };

    const handleGlobalDrop = (e: DragEvent) => {
      // Prevent default to handle invalid drops
      e.preventDefault();
    };

    if (draggedPage) {
      document.addEventListener('dragend', handleGlobalDragEnd);
      document.addEventListener('drop', handleGlobalDrop);
    }

    return () => {
      document.removeEventListener('dragend', handleGlobalDragEnd);
      document.removeEventListener('drop', handleGlobalDrop);
    };
  }, [draggedPage]);

  const selectAll = useCallback(() => {
    if (mergedPdfDocument) {
      setSelectedPages(mergedPdfDocument.pages.map(p => p.pageNumber));
    }
  }, [mergedPdfDocument, setSelectedPages]);

  const deselectAll = useCallback(() => setSelectedPages([]), [setSelectedPages]);

  const togglePage = useCallback((pageNumber: number) => {
    console.log('🔄 Toggling page', pageNumber);

    // Check if currently selected and update accordingly
    const isCurrentlySelected = selectedPageNumbers.includes(pageNumber);

    if (isCurrentlySelected) {
      // Remove from selection
      console.log('🔄 Removing page', pageNumber);
      const newSelectedPageNumbers = selectedPageNumbers.filter(num => num !== pageNumber);
      setSelectedPages(newSelectedPageNumbers);
    } else {
      // Add to selection
      console.log('🔄 Adding page', pageNumber);
      const newSelectedPageNumbers = [...selectedPageNumbers, pageNumber];
      setSelectedPages(newSelectedPageNumbers);
    }
  }, [selectedPageNumbers, setSelectedPages]);

  const toggleSelectionMode = useCallback(() => {
    setSelectionMode(prev => {
      const newMode = !prev;
      if (!newMode) {
        // Clear selections when exiting selection mode
        setSelectedPages([]);
        setCsvInput("");
      }
      return newMode;
    });
  }, []);

  const parseCSVInput = useCallback((csv: string) => {
    if (!mergedPdfDocument) return [];

    const pageNumbers: number[] = [];
    const ranges = csv.split(',').map(s => s.trim()).filter(Boolean);

    ranges.forEach(range => {
      if (range.includes('-')) {
        const [start, end] = range.split('-').map(n => parseInt(n.trim()));
        for (let i = start; i <= end && i <= mergedPdfDocument.totalPages; i++) {
          if (i > 0) {
            pageNumbers.push(i);
          }
        }
      } else {
        const pageNum = parseInt(range);
        if (pageNum > 0 && pageNum <= mergedPdfDocument.totalPages) {
          pageNumbers.push(pageNum);
        }
      }
    });

    return pageNumbers;
  }, [mergedPdfDocument]);

  const updatePagesFromCSV = useCallback(() => {
    const pageNumbers = parseCSVInput(csvInput);
    setSelectedPages(pageNumbers);
  }, [csvInput, parseCSVInput, setSelectedPages]);

  const handleDragStart = useCallback((pageNumber: number) => {
    setDraggedPage(pageNumber);

    // Check if this is a multi-page drag in selection mode
    if (selectionMode && selectedPageNumbers.includes(pageNumber) && selectedPageNumbers.length > 1) {
      setMultiPageDrag({
        pageNumbers: selectedPageNumbers,
        count: selectedPageNumbers.length
      });
    } else {
      setMultiPageDrag(null);
    }
  }, [selectionMode, selectedPageNumbers]);

  const handleDragEnd = useCallback(() => {
    // Clean up drag state regardless of where the drop happened
    setDraggedPage(null);
    setDropTarget(null);
    setMultiPageDrag(null);
    setDragPosition(null);
  }, []);

  const handleDragOver = useCallback((e: React.DragEvent) => {
    e.preventDefault();

    if (!draggedPage) return;

    // Update drag position for multi-page indicator
    if (multiPageDrag) {
      setDragPosition({ x: e.clientX, y: e.clientY });
    }

    // Get the element under the mouse cursor
    const elementUnderCursor = document.elementFromPoint(e.clientX, e.clientY);
    if (!elementUnderCursor) return;

    // Find the closest page container
    const pageContainer = elementUnderCursor.closest('[data-page-number]');
    if (pageContainer) {
      const pageNumberStr = pageContainer.getAttribute('data-page-number');
      const pageNumber = pageNumberStr ? parseInt(pageNumberStr) : null;
      if (pageNumber && pageNumber !== draggedPage) {
        setDropTarget(pageNumber);
        return;
      }
    }

    // Check if over the end zone
    const endZone = elementUnderCursor.closest('[data-drop-zone="end"]');
    if (endZone) {
      setDropTarget('end');
      return;
    }

    // If not over any valid drop target, clear it
    setDropTarget(null);
  }, [draggedPage, multiPageDrag]);

  const handleDragEnter = useCallback((pageNumber: number) => {
    if (draggedPage && pageNumber !== draggedPage) {
      setDropTarget(pageNumber);
    }
  }, [draggedPage]);

  const handleDragLeave = useCallback(() => {
    // Don't clear drop target on drag leave - let dragover handle it
  }, []);

  // Update PDF document state with edit tracking
  const setPdfDocument = useCallback((updatedDoc: PDFDocument) => {
    console.log('setPdfDocument called - setting edited state');

    // Update local edit state for immediate visual feedback
    setEditedDocument(updatedDoc);
    setHasUnsavedChanges(true); // Use global state
    setHasUnsavedDraft(true); // Mark that we have unsaved draft changes

    // Auto-save to drafts (debounced) - only if we have new changes
    if (autoSaveTimer.current) {
      clearTimeout(autoSaveTimer.current);
    }

    autoSaveTimer.current = setTimeout(() => {
      if (hasUnsavedDraft) {
        saveDraftToIndexedDB(updatedDoc);
        setHasUnsavedDraft(false); // Mark draft as saved
      }
    }, 30000); // Auto-save after 30 seconds of inactivity

    return updatedDoc;
  }, [setHasUnsavedChanges, hasUnsavedDraft]);

  // Save draft to separate IndexedDB location
  const saveDraftToIndexedDB = useCallback(async (doc: PDFDocument) => {
    try {
      const draftKey = `draft-${doc.id || 'merged'}`;
      const draftData = {
        document: doc,
        timestamp: Date.now(),
        originalFiles: activeFiles.map(f => f.name)
      };

      // Save to 'pdf-drafts' store in IndexedDB
      const request = indexedDB.open('stirling-pdf-drafts', 1);
      request.onupgradeneeded = () => {
        const db = request.result;
        if (!db.objectStoreNames.contains('drafts')) {
          db.createObjectStore('drafts');
        }
      };

      request.onsuccess = () => {
        const db = request.result;
        const transaction = db.transaction('drafts', 'readwrite');
        const store = transaction.objectStore('drafts');
        store.put(draftData, draftKey);
        console.log('Draft auto-saved to IndexedDB');
      };
    } catch (error) {
      console.warn('Failed to auto-save draft:', error);
    }
  }, [activeFiles]);

  // Clean up draft from IndexedDB
  const cleanupDraft = useCallback(async () => {
    try {
      const draftKey = `draft-${mergedPdfDocument?.id || 'merged'}`;
      const request = indexedDB.open('stirling-pdf-drafts', 1);

      request.onsuccess = () => {
        const db = request.result;
        const transaction = db.transaction('drafts', 'readwrite');
        const store = transaction.objectStore('drafts');
        store.delete(draftKey);
      };
    } catch (error) {
      console.warn('Failed to cleanup draft:', error);
    }
  }, [mergedPdfDocument]);

  // Apply changes to create new processed file
  const applyChanges = useCallback(async () => {
    if (!editedDocument || !mergedPdfDocument) return;

    try {
      if (activeFiles.length === 1) {
        const file = activeFiles[0];
        const currentProcessedFile = processedFiles.get(file);

        if (currentProcessedFile) {
          const updatedProcessedFile = {
            ...currentProcessedFile,
            id: `${currentProcessedFile.id}-edited-${Date.now()}`,
            pages: editedDocument.pages.map(page => ({
              ...page,
              rotation: page.rotation || 0,
              splitBefore: page.splitBefore || false
            })),
            totalPages: editedDocument.pages.length,
            lastModified: Date.now()
          };

          updateProcessedFile(file, updatedProcessedFile);
        }
      } else if (activeFiles.length > 1) {
        setStatus('Apply changes for multiple files not yet supported');
        return;
      }

      // Wait for the processed file update to complete before clearing edit state
      setTimeout(() => {
        setEditedDocument(null);
        setHasUnsavedChanges(false);
        setHasUnsavedDraft(false);
        cleanupDraft();
        setStatus('Changes applied successfully');
      }, 100);

    } catch (error) {
      console.error('Failed to apply changes:', error);
      setStatus('Failed to apply changes');
    }
  }, [editedDocument, mergedPdfDocument, processedFiles, activeFiles, updateProcessedFile, setHasUnsavedChanges, setStatus, cleanupDraft]);

  const animateReorder = useCallback((pageNumber: number, targetIndex: number) => {
    if (!displayDocument || isAnimating) return;

    // In selection mode, if the dragged page is selected, move all selected pages
    const pagesToMove = selectionMode && selectedPageNumbers.includes(pageNumber)
      ? selectedPageNumbers.map(num => {
          const page = displayDocument.pages.find(p => p.pageNumber === num);
          return page?.id || '';
        }).filter(id => id)
      : [displayDocument.pages.find(p => p.pageNumber === pageNumber)?.id || ''].filter(id => id);

    const originalIndex = displayDocument.pages.findIndex(p => p.pageNumber === pageNumber);
    if (originalIndex === -1 || originalIndex === targetIndex) return;

    // Skip animation for large documents (500+ pages) to improve performance
    const isLargeDocument = displayDocument.pages.length > 500;

    if (isLargeDocument) {
      // For large documents, just execute the command without animation
      if (pagesToMove.length > 1) {
        const command = new MovePagesCommand(displayDocument, setPdfDocument, pagesToMove, targetIndex);
        executeCommand(command);
      } else {
        const pageId = pagesToMove[0];
        const command = new ReorderPageCommand(displayDocument, setPdfDocument, pageId, targetIndex);
        executeCommand(command);
      }
      return;
    }

    setIsAnimating(true);

    // For smaller documents, determine which pages might be affected by the move
    const startIndex = Math.min(originalIndex, targetIndex);
    const endIndex = Math.max(originalIndex, targetIndex);
    const affectedPageIds = displayDocument.pages
      .slice(Math.max(0, startIndex - 5), Math.min(displayDocument.pages.length, endIndex + 5))
      .map(p => p.id);

    // Only capture positions for potentially affected pages
    const currentPositions = new Map<string, { x: number; y: number }>();

    affectedPageIds.forEach(pageId => {
      const element = document.querySelector(`[data-page-number="${pageId}"]`);
      if (element) {
        const rect = element.getBoundingClientRect();
        currentPositions.set(pageId, { x: rect.left, y: rect.top });
      }
    });

    // Execute the reorder command
    if (pagesToMove.length > 1) {
      const command = new MovePagesCommand(displayDocument, setPdfDocument, pagesToMove, targetIndex);
      executeCommand(command);
    } else {
      const pageId = pagesToMove[0];
      const command = new ReorderPageCommand(displayDocument, setPdfDocument, pageId, targetIndex);
      executeCommand(command);
    }

    // Animate only the affected pages
    setTimeout(() => {
      requestAnimationFrame(() => {
        requestAnimationFrame(() => {
          const newPositions = new Map<string, { x: number; y: number }>();

          // Get new positions only for affected pages
          affectedPageIds.forEach(pageId => {
            const element = document.querySelector(`[data-page-number="${pageId}"]`);
            if (element) {
              const rect = element.getBoundingClientRect();
              newPositions.set(pageId, { x: rect.left, y: rect.top });
            }
          });

          const elementsToAnimate: HTMLElement[] = [];

          // Apply animations only to pages that actually moved
          affectedPageIds.forEach(pageId => {
            const element = document.querySelector(`[data-page-number="${pageId}"]`) as HTMLElement;
            if (!element) return;

            const currentPos = currentPositions.get(pageId);
            const newPos = newPositions.get(pageId);

            if (currentPos && newPos) {
              const deltaX = currentPos.x - newPos.x;
              const deltaY = currentPos.y - newPos.y;

              if (Math.abs(deltaX) > 1 || Math.abs(deltaY) > 1) {
                elementsToAnimate.push(element);

                // Apply initial transform
                element.style.transform = `translate(${deltaX}px, ${deltaY}px)`;
                element.style.transition = 'none';

                // Force reflow
                element.offsetHeight;

                // Animate to final position
                element.style.transition = 'transform 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94)';
                element.style.transform = 'translate(0px, 0px)';
              }
            }
          });

          // Clean up after animation (only for animated elements)
          setTimeout(() => {
            elementsToAnimate.forEach((element) => {
              element.style.transform = '';
              element.style.transition = '';
            });
            setIsAnimating(false);
          }, 300);
        });
      });
    }, 10); // Small delay to allow state update
  }, [displayDocument, isAnimating, executeCommand, selectionMode, selectedPageNumbers, setPdfDocument]);

  const handleDrop = useCallback((e: React.DragEvent, targetPageNumber: number | 'end') => {
    e.preventDefault();
    if (!draggedPage || !displayDocument || draggedPage === targetPageNumber) return;

    let targetIndex: number;
    if (targetPageNumber === 'end') {
      targetIndex = displayDocument.pages.length;
    } else {
      targetIndex = displayDocument.pages.findIndex(p => p.pageNumber === targetPageNumber);
      if (targetIndex === -1) return;
    }

    animateReorder(draggedPage, targetIndex);

    setDraggedPage(null);
    setDropTarget(null);
    setMultiPageDrag(null);
    setDragPosition(null);

    const moveCount = multiPageDrag ? multiPageDrag.count : 1;
    setStatus(`${moveCount > 1 ? `${moveCount} pages` : 'Page'} reordered`);
  }, [draggedPage, displayDocument, animateReorder, multiPageDrag]);

  const handleEndZoneDragEnter = useCallback(() => {
    if (draggedPage) {
      setDropTarget('end');
    }
  }, [draggedPage]);

  const handleRotate = useCallback((direction: 'left' | 'right') => {
    if (!displayDocument) return;

    const rotation = direction === 'left' ? -90 : 90;
    const pagesToRotate = selectionMode
      ? selectedPageNumbers.map(pageNum => {
          const page = displayDocument.pages.find(p => p.pageNumber === pageNum);
          return page?.id || '';
        }).filter(id => id)
      : displayDocument.pages.map(p => p.id);

    if (selectionMode && selectedPageNumbers.length === 0) return;

    const command = new RotatePagesCommand(
      displayDocument,
      setPdfDocument,
      pagesToRotate,
      rotation
    );

    executeCommand(command);
    const pageCount = selectionMode ? selectedPageNumbers.length : displayDocument.pages.length;
    setStatus(`Rotated ${pageCount} pages ${direction}`);
  }, [displayDocument, selectedPageNumbers, selectionMode, executeCommand, setPdfDocument]);

  const handleDelete = useCallback(() => {
    if (!displayDocument) return;

    const pagesToDelete = selectionMode
      ? selectedPageNumbers.map(pageNum => {
          const page = displayDocument.pages.find(p => p.pageNumber === pageNum);
          return page?.id || '';
        }).filter(id => id)
      : displayDocument.pages.map(p => p.id);

    if (selectionMode && selectedPageNumbers.length === 0) return;

    const command = new DeletePagesCommand(
      displayDocument,
      setPdfDocument,
      pagesToDelete
    );

    executeCommand(command);
    if (selectionMode) {
      setSelectedPages([]);
    }
    const pageCount = selectionMode ? selectedPageNumbers.length : displayDocument.pages.length;
    setStatus(`Deleted ${pageCount} pages`);
  }, [displayDocument, selectedPageNumbers, selectionMode, executeCommand, setPdfDocument, setSelectedPages]);

  const handleSplit = useCallback(() => {
    if (!displayDocument) return;

    const pagesToSplit = selectionMode
      ? selectedPageNumbers.map(pageNum => {
          const page = displayDocument.pages.find(p => p.pageNumber === pageNum);
          return page?.id || '';
        }).filter(id => id)
      : displayDocument.pages.map(p => p.id);

    if (selectionMode && selectedPageNumbers.length === 0) return;

    const command = new ToggleSplitCommand(
      displayDocument,
      setPdfDocument,
      pagesToSplit
    );

    executeCommand(command);
    const pageCount = selectionMode ? selectedPageNumbers.length : displayDocument.pages.length;
    setStatus(`Split markers toggled for ${pageCount} pages`);
  }, [displayDocument, selectedPageNumbers, selectionMode, executeCommand, setPdfDocument]);

  const showExportPreview = useCallback((selectedOnly: boolean = false) => {
    if (!mergedPdfDocument) return;

    // Convert page numbers to page IDs for export service
    const exportPageIds = selectedOnly
      ? selectedPageNumbers.map(pageNum => {
          const page = mergedPdfDocument.pages.find(p => p.pageNumber === pageNum);
          return page?.id || '';
        }).filter(id => id)
      : [];

    const preview = pdfExportService.getExportInfo(mergedPdfDocument, exportPageIds, selectedOnly);
    setExportPreview(preview);
    setShowExportModal(true);
  }, [mergedPdfDocument, selectedPageNumbers]);

  const handleExport = useCallback(async (selectedOnly: boolean = false) => {
    if (!mergedPdfDocument) return;

    setExportLoading(true);
    try {
      // Convert page numbers to page IDs for export service
      const exportPageIds = selectedOnly
        ? selectedPageNumbers.map(pageNum => {
            const page = mergedPdfDocument.pages.find(p => p.pageNumber === pageNum);
            return page?.id || '';
          }).filter(id => id)
        : [];

      const errors = pdfExportService.validateExport(mergedPdfDocument, exportPageIds, selectedOnly);
      if (errors.length > 0) {
        setStatus(errors.join(', '));
        return;
      }

      const hasSplitMarkers = mergedPdfDocument.pages.some(page => page.splitBefore);

      if (hasSplitMarkers) {
        const result = await pdfExportService.exportPDF(mergedPdfDocument, exportPageIds, {
          selectedOnly,
          filename,
          splitDocuments: true
        }) as { blobs: Blob[]; filenames: string[] };

        result.blobs.forEach((blob, index) => {
          setTimeout(() => {
            pdfExportService.downloadFile(blob, result.filenames[index]);
          }, index * 500);
        });

        setStatus(`Exported ${result.blobs.length} split documents`);
      } else {
        const result = await pdfExportService.exportPDF(mergedPdfDocument, exportPageIds, {
          selectedOnly,
          filename
        }) as { blob: Blob; filename: string };

        pdfExportService.downloadFile(result.blob, result.filename);
        setStatus('PDF exported successfully');
      }
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : 'Export failed';
      setStatus(errorMessage);
    } finally {
      setExportLoading(false);
    }
  }, [mergedPdfDocument, selectedPageNumbers, filename]);

  const handleUndo = useCallback(() => {
    if (undo()) {
      setStatus('Operation undone');
    }
  }, [undo]);

  const handleRedo = useCallback(() => {
    if (redo()) {
      setStatus('Operation redone');
    }
  }, [redo]);

  const closePdf = useCallback(() => {
    // Use global navigation guard system
    fileContext.requestNavigation(() => {
      clearAllFiles(); // This now handles all cleanup centrally (including merged docs)
      setSelectedPages([]);
    });
  }, [fileContext, clearAllFiles, setSelectedPages]);

  // PageEditorControls needs onExportSelected and onExportAll
  const onExportSelected = useCallback(() => showExportPreview(true), [showExportPreview]);
  const onExportAll = useCallback(() => showExportPreview(false), [showExportPreview]);

  // Expose functions to parent component for PageEditorControls
  useEffect(() => {
    if (onFunctionsReady) {
      onFunctionsReady({
        handleUndo,
        handleRedo,
        canUndo,
        canRedo,
        handleRotate,
        handleDelete,
        handleSplit,
        showExportPreview,
        onExportSelected,
        onExportAll,
        exportLoading,
        selectionMode,
        selectedPages: selectedPageNumbers,
        closePdf,
      });
    }
  }, [
    onFunctionsReady,
    handleUndo,
    handleRedo,
    canUndo,
    canRedo,
    handleRotate,
    handleDelete,
    handleSplit,
    showExportPreview,
    onExportSelected,
    onExportAll,
    exportLoading,
    selectionMode,
    selectedPageNumbers,
    closePdf
  ]);

  // Show loading or empty state instead of blocking
  const showLoading = !mergedPdfDocument && (globalProcessing || activeFiles.length > 0);
  const showEmpty = !mergedPdfDocument && !globalProcessing && activeFiles.length === 0;
  // Functions for global NavigationWarningModal
  const handleApplyAndContinue = useCallback(async () => {
    if (editedDocument) {
      await applyChanges();
    }
  }, [editedDocument, applyChanges]);

  const handleExportAndContinue = useCallback(async () => {
    if (editedDocument) {
      await applyChanges();
      await handleExport(false);
    }
  }, [editedDocument, applyChanges, handleExport]);

  // Check for existing drafts
  const checkForDrafts = useCallback(async () => {
    if (!mergedPdfDocument) return;

    try {
      const draftKey = `draft-${mergedPdfDocument.id || 'merged'}`;
      const request = indexedDB.open('stirling-pdf-drafts', 1);

      request.onsuccess = () => {
        const db = request.result;
        if (!db.objectStoreNames.contains('drafts')) return;

        const transaction = db.transaction('drafts', 'readonly');
        const store = transaction.objectStore('drafts');
        const getRequest = store.get(draftKey);

        getRequest.onsuccess = () => {
          const draft = getRequest.result;
          if (draft && draft.timestamp) {
            // Check if draft is recent (within last 24 hours)
            const draftAge = Date.now() - draft.timestamp;
            const twentyFourHours = 24 * 60 * 60 * 1000;

            if (draftAge < twentyFourHours) {
              setFoundDraft(draft);
              setShowResumeModal(true);
            }
          }
        };
      };
    } catch (error) {
      console.warn('Failed to check for drafts:', error);
    }
  }, [mergedPdfDocument]);

  // Resume work from draft
  const resumeWork = useCallback(() => {
    if (foundDraft && foundDraft.document) {
      setEditedDocument(foundDraft.document);
      setHasUnsavedChanges(true);
      setFoundDraft(null);
      setShowResumeModal(false);
      setStatus('Resumed previous work');
    }
  }, [foundDraft]);

  // Start fresh (ignore draft)
  const startFresh = useCallback(() => {
    if (foundDraft) {
      // Clean up the draft
      cleanupDraft();
    }
    setFoundDraft(null);
    setShowResumeModal(false);
  }, [foundDraft, cleanupDraft]);

  // Cleanup on unmount
  useEffect(() => {
    return () => {
      console.log('PageEditor unmounting - cleaning up resources');

      // Clear auto-save timer
      if (autoSaveTimer.current) {
        clearTimeout(autoSaveTimer.current);
      }

      // Clean up draft if component unmounts with unsaved changes
      if (hasUnsavedChanges) {
        cleanupDraft();
      }
    };
  }, [hasUnsavedChanges, cleanupDraft]);

  // Check for drafts when document loads
  useEffect(() => {
    if (mergedPdfDocument && !editedDocument && !hasUnsavedChanges) {
      // Small delay to let the component settle
      setTimeout(checkForDrafts, 1000);
    }
  }, [mergedPdfDocument, editedDocument, hasUnsavedChanges, checkForDrafts]);

  // Global navigation intercept - listen for navigation events
  useEffect(() => {
    if (!hasUnsavedChanges) return;

    const handleBeforeUnload = (e: BeforeUnloadEvent) => {
      e.preventDefault();
      e.returnValue = 'You have unsaved changes. Are you sure you want to leave?';
      return 'You have unsaved changes. Are you sure you want to leave?';
    };

    // Intercept browser navigation
    window.addEventListener('beforeunload', handleBeforeUnload);

    return () => {
      window.removeEventListener('beforeunload', handleBeforeUnload);
    };
  }, [hasUnsavedChanges]);

  // Display all pages - use edited or original document
  const displayedPages = displayDocument?.pages || [];

  return (
    <Box pos="relative" h="100vh" style={{ overflow: 'auto' }}>
      <LoadingOverlay visible={globalProcessing && !mergedPdfDocument} />

      {showEmpty && (
        <Center h="100vh">
          <Stack align="center" gap="md">
            <Text size="lg" c="dimmed">📄</Text>
            <Text c="dimmed">No PDF files loaded</Text>
            <Text size="sm" c="dimmed">Add files to start editing pages</Text>
          </Stack>
        </Center>
      )}

      {showLoading && (
        <Box p="md" pt="xl">
          <SkeletonLoader type="controls" />

          {/* Progress indicator */}
          <Box mb="md" p="sm" style={{ backgroundColor: 'var(--mantine-color-blue-0)', borderRadius: 8 }}>
            <Group justify="space-between" mb="xs">
              <Text size="sm" fw={500}>
                Processing PDF files...
              </Text>
              <Text size="sm" c="dimmed">
                {Math.round(processingProgress || 0)}%
              </Text>
            </Group>
            <div style={{
              width: '100%',
              height: '4px',
              backgroundColor: 'var(--mantine-color-gray-2)',
              borderRadius: '2px',
              overflow: 'hidden'
            }}>
              <div style={{
                width: `${Math.round(processingProgress || 0)}%`,
                height: '100%',
                backgroundColor: 'var(--mantine-color-blue-6)',
                transition: 'width 0.3s ease'
              }} />
            </div>
          </Box>

          <SkeletonLoader type="pageGrid" count={8} />
        </Box>
      )}

      {displayDocument && (
        <Box p="md" pt="xl">
          {/* Enhanced Processing Status */}
          {globalProcessing && processingProgress < 100 && (
            <Box mb="md" p="sm" style={{ backgroundColor: 'var(--mantine-color-blue-0)', borderRadius: 8 }}>
              <Group justify="space-between" mb="xs">
                <Text size="sm" fw={500}>Processing thumbnails...</Text>
                <Text size="sm" c="dimmed">{Math.round(processingProgress || 0)}%</Text>
              </Group>
              <div style={{
                width: '100%',
                height: '4px',
                backgroundColor: 'var(--mantine-color-gray-2)',
                borderRadius: '2px',
                overflow: 'hidden'
              }}>
                <div style={{
                  width: `${Math.round(processingProgress || 0)}%`,
                  height: '100%',
                  backgroundColor: 'var(--mantine-color-blue-6)',
                  transition: 'width 0.3s ease'
                }} />
              </div>
            </Box>
          )}

          <Group mb="md">
            <TextInput
              value={filename}
              onChange={(e) => setFilename(e.target.value)}
              placeholder="Enter filename"
              style={{ minWidth: 200 }}
            />
            <Button
              onClick={toggleSelectionMode}
              variant={selectionMode ? "filled" : "outline"}
              color={selectionMode ? "blue" : "gray"}
              styles={{
                root: {
                  transition: 'all 0.2s ease',
                  ...(selectionMode && {
                    boxShadow: '0 2px 8px rgba(59, 130, 246, 0.3)',
                  })
                }
              }}
            >
              {selectionMode ? "Exit Selection" : "Select Pages"}
            </Button>
            {selectionMode && (
              <>
                <Button onClick={selectAll} variant="light">Select All</Button>
                <Button onClick={deselectAll} variant="light">Deselect All</Button>
              </>
            )}

            {/* Apply Changes Button */}
            {hasUnsavedChanges && (
              <Button
                onClick={applyChanges}
                color="green"
                variant="filled"
                style={{ marginLeft: 'auto' }}
              >
                Apply Changes
              </Button>
            )}
          </Group>

          {selectionMode && (
            <BulkSelectionPanel
              csvInput={csvInput}
              setCsvInput={setCsvInput}
              selectedPages={selectedPageNumbers}
              onUpdatePagesFromCSV={updatePagesFromCSV}
            />
          )}


        <DragDropGrid
          items={displayedPages}
          selectedItems={selectedPageNumbers}
          selectionMode={selectionMode}
          isAnimating={isAnimating}
          onDragStart={handleDragStart}
          onDragEnd={handleDragEnd}
          onDragOver={handleDragOver}
          onDragEnter={handleDragEnter}
          onDragLeave={handleDragLeave}
          onDrop={handleDrop}
          onEndZoneDragEnter={handleEndZoneDragEnter}
          draggedItem={draggedPage}
          dropTarget={dropTarget}
          multiItemDrag={multiPageDrag}
          dragPosition={dragPosition}
          renderItem={(page, index, refs) => (
            <PageThumbnail
              page={page}
              index={index}
              totalPages={displayDocument.pages.length}
              originalFile={activeFiles.length === 1 ? activeFiles[0] : undefined}
              selectedPages={selectedPageNumbers}
              selectionMode={selectionMode}
              draggedPage={draggedPage}
              dropTarget={dropTarget === 'end' ? null : dropTarget}
              movingPage={movingPage}
              isAnimating={isAnimating}
              pageRefs={refs}
              onDragStart={handleDragStart}
              onDragEnd={handleDragEnd}
              onDragOver={handleDragOver}
              onDragEnter={handleDragEnter}
              onDragLeave={handleDragLeave}
              onDrop={handleDrop}
              onTogglePage={togglePage}
              onAnimateReorder={animateReorder}
              onExecuteCommand={executeCommand}
              onSetStatus={setStatus}
              onSetMovingPage={setMovingPage}
              RotatePagesCommand={RotatePagesCommand}
              DeletePagesCommand={DeletePagesCommand}
              ToggleSplitCommand={ToggleSplitCommand}
              pdfDocument={displayDocument}
              setPdfDocument={setPdfDocument}
            />
          )}
          renderSplitMarker={(page, index) => (
            <div
              style={{
                width: '2px',
                height: '20rem',
                borderLeft: '2px dashed #3b82f6',
                backgroundColor: 'transparent',
                marginLeft: '-0.75rem',
                marginRight: '-0.75rem',
                flexShrink: 0
              }}
            />
          )}
        />

        </Box>
      )}

      {/* Modal should be outside the conditional but inside the main container */}
      <Modal
          opened={showExportModal}
          onClose={() => setShowExportModal(false)}
          title="Export Preview"
        >
          {exportPreview && (
            <Stack gap="md">
              <Group justify="space-between">
                <Text>Pages to export:</Text>
                <Text fw={500}>{exportPreview.pageCount}</Text>
              </Group>

              {exportPreview.splitCount > 1 && (
                <Group justify="space-between">
                  <Text>Split into documents:</Text>
                  <Text fw={500}>{exportPreview.splitCount}</Text>
                </Group>
              )}

              <Group justify="space-between">
                <Text>Estimated size:</Text>
                <Text fw={500}>{exportPreview.estimatedSize}</Text>
              </Group>

              {mergedPdfDocument && mergedPdfDocument.pages.some(p => p.splitBefore) && (
                <Alert color="blue">
                  This will create multiple PDF files based on split markers.
                </Alert>
              )}

              <Group justify="flex-end" mt="md">
                <Button
                  variant="light"
                  onClick={() => setShowExportModal(false)}
                >
                  Cancel
                </Button>
                <Button
                  color="green"
                  loading={exportLoading}
                  onClick={() => {
                    setShowExportModal(false);
                    const selectedOnly = exportPreview.pageCount < (mergedPdfDocument?.totalPages || 0);
                    handleExport(selectedOnly);
                  }}
                >
                  Export PDF
                </Button>
              </Group>
            </Stack>
          )}
        </Modal>

        {/* Global Navigation Warning Modal */}
        <NavigationWarningModal
          onApplyAndContinue={handleApplyAndContinue}
          onExportAndContinue={handleExportAndContinue}
        />

        {/* Resume Work Modal */}
        <Modal
          opened={showResumeModal}
          onClose={startFresh}
          title="Resume Work"
          centered
          closeOnClickOutside={false}
          closeOnEscape={false}
        >
          <Stack gap="md">
            <Text>
              We found unsaved changes from a previous session. Would you like to resume where you left off?
            </Text>

            {foundDraft && (
              <Text size="sm" c="dimmed">
                Last saved: {new Date(foundDraft.timestamp).toLocaleString()}
              </Text>
            )}

            <Group justify="flex-end" gap="sm">
              <Button
                variant="light"
                color="gray"
                onClick={startFresh}
              >
                Start Fresh
              </Button>

              <Button
                color="blue"
                onClick={resumeWork}
              >
                Resume Work
              </Button>
            </Group>
          </Stack>
        </Modal>

      {status && (
        <Notification
          color="blue"
          mt="md"
          onClose={() => setStatus(null)}
          style={{ position: 'fixed', bottom: 20, right: 20, zIndex: 1000 }}
        >
          {status}
        </Notification>
      )}
    </Box>
  );
};

export default PageEditor;
