import { useState, useEffect, useCallback, useRef } from "react";
import { useParams, useNavigate } from "react-router-dom";
import {
  useQuery,
  useQueries,
  useMutation,
  useQueryClient,
} from "@tanstack/react-query";
import { v4 as uuidv4 } from "uuid";
import { useHistory } from "../hooks/useHistory";
import { usePanelLayout } from "../hooks/usePanelLayout";
import { useCollaborationRoom } from "../contexts/CollaborationContext";
import type {
  DataChangeMessage,
  ItemCreatedMessage,
  ItemDeletedMessage,
} from "../services/collaboration";
import {
  Box,
  CircularProgress,
  Dialog,
  DialogTitle,
  DialogContent,
  DialogActions,
  Button,
  TextField,
  FormControl,
  InputLabel,
  Select,
  MenuItem,
  Alert,
  Snackbar,
  useMediaQuery,
  useTheme,
  IconButton,
  BottomNavigation,
  BottomNavigationAction,
  Paper,
  SwipeableDrawer,
  Typography,
} from "@mui/material";
import {
  Storage as DataIcon,
  Settings as SettingsIcon,
  Description as PageIcon,
  Close as CloseIcon,
  Layers as LayersIcon,
} from "@mui/icons-material";
import EditorCanvas, {
  type ContextMenuEvent,
  type EditorCanvasRef,
} from "../components/reportEditor/EditorCanvas";
import EditorToolbar, {
  type SnapOptions,
} from "../components/reportEditor/EditorToolbar";
import ContextMenu from "../components/reportEditor/ContextMenu";
import PropertiesPanel from "../components/reportEditor/PropertiesPanel";
import DataBindingPanel from "../components/reportEditor/DataBindingPanel";
import DatasetSelector from "../components/reportEditor/DatasetSelector";
import PreviewDialog from "../components/reportEditor/PreviewDialog";
import DatasetManagerDialog from "../components/reportEditor/DatasetManagerDialog";
import ImageUploadDialog, {
  type ImageData,
} from "../components/reportEditor/ImageUploadDialog";
import PageNavigator from "../components/reportEditor/PageNavigator";
import ResizablePanel from "../components/reportEditor/ResizablePanel";
import SidebarDropZone from "../components/reportEditor/SidebarDropZone";
import {
  reportTemplateService,
  reportFontService,
  reportGeneratorService,
  virtualDatasetService,
  openBlobInNewTab,
} from "../services/reportService";
import type {
  AprtTemplate,
  AprtElement,
  AprtPage,
  ElementType,
  PageSize,
  PageOrientation,
  AprtMargins,
  DataSchemaDto,
  DatasetTypeDto,
  DataSourceSelection,
  ReportTemplateDto,
} from "../types/report";
import {
  defaultTemplate,
  defaultStyle,
  defaultImageSettings,
  defaultPage,
} from "../types/report";

// Panel types for mobile navigation
type MobilePanel = "pages" | "data" | "properties" | null;

export default function ReportEditorPage() {
  const { id } = useParams<{ id: string }>();
  const navigate = useNavigate();
  const queryClient = useQueryClient();
  const isNew = !id;
  const theme = useTheme();

  // Responsive breakpoints
  const isMobile = useMediaQuery(theme.breakpoints.down("sm")); // < 600px
  const isTablet = useMediaQuery(theme.breakpoints.between("sm", "lg")); // 600-1200px

  // Template state with robust undo/redo (100 states history)
  const [templateHistory, historyActions] = useHistory<AprtTemplate>(
    defaultTemplate,
    { maxHistoryLength: 100 },
  );
  const template = templateHistory.current;

  const [templateInfo, setTemplateInfo] = useState<{
    nome: string;
    descrizione: string;
    categoria: string;
  }>({
    nome: "Nuovo Template",
    descrizione: "",
    categoria: "Generale",
  });

  // Dataset state
  const [selectedDatasets, setSelectedDatasets] = useState<DatasetTypeDto[]>(
    [],
  );

  // Page state - track which page is currently being edited
  const [currentPageId, setCurrentPageId] = useState<string>(defaultPage.id);

  // Editor state - support multiple selection
  const [selectedElementIds, setSelectedElementIds] = useState<string[]>([]);
  const [zoom, setZoom] = useState(isMobile ? 0.5 : 1);
  const [showGrid, setShowGrid] = useState(true);
  const [snapOptions, setSnapOptions] = useState<SnapOptions>({
    grid: false,
    objects: true,
    borders: true,
    center: true,
    tangent: true,
  });
  const [gridSize] = useState(5); // 5mm grid

  // Mobile panel state
  const [mobilePanel, setMobilePanel] = useState<MobilePanel>(null);

  // Panel layout configuration (persisted to localStorage)
  const panelLayout = usePanelLayout();

  // Handle panel drag and drop between sidebars
  const handlePanelDrop = useCallback(
    (
      panelId: string,
      targetPosition: "left" | "right",
      targetIndex: number,
    ) => {
      panelLayout.movePanelToPosition(panelId, targetPosition, targetIndex);
    },
    [panelLayout],
  );

  // UI state
  const [saveDialog, setSaveDialog] = useState(false);
  const [previewDialog, setPreviewDialog] = useState(false);
  const [datasetManagerDialog, setDatasetManagerDialog] = useState(false);
  const [imageUploadDialog, setImageUploadDialog] = useState(false);
  const [isGeneratingPreview, setIsGeneratingPreview] = useState(false);
  const [snackbar, setSnackbar] = useState<{
    open: boolean;
    message: string;
    severity: "success" | "error";
  }>({
    open: false,
    message: "",
    severity: "success",
  });

  // Context menu state
  const [contextMenu, setContextMenu] = useState<{
    open: boolean;
    position: { x: number; y: number } | null;
  }>({
    open: false,
    position: null,
  });
  const [clipboard, setClipboard] = useState<AprtElement | null>(null);

  // Track unsaved changes - reset when saved, set when modified
  const [lastSavedUndoCount, setLastSavedUndoCount] = useState(0);
  const hasUnsavedChanges = templateHistory.undoCount !== lastSavedUndoCount;

  // Auto-save feature - enabled by default
  const [autoSaveEnabled, setAutoSaveEnabled] = useState(true);

  // Template version for collaboration sync (increments on each save)
  const templateVersionRef = useRef(0);

  // Ref to EditorCanvas for checking text editing state
  const canvasRef = useRef<EditorCanvasRef>(null);

  // ============ COLLABORATION (using global context) ============
  // Room key format: "report-template:{id}"
  const roomKey = id ? `report-template:${id}` : null;
  const collaboration = useCollaborationRoom(roomKey, {
    enabled: !isNew && !!id,
  });

  // Flag to prevent re-broadcasting received changes
  const isApplyingRemoteChange = useRef(false);

  // Update zoom on screen size change
  useEffect(() => {
    if (isMobile) {
      setZoom(0.5);
    } else if (isTablet) {
      setZoom(0.75);
    } else {
      setZoom(1);
    }
  }, [isMobile, isTablet]);

  // ============ COLLABORATION EFFECTS ============
  // The collaboration context handles connection, room joining, and presence automatically.
  // We only need to subscribe to data change events and send our changes.

  // Subscribe to remote data changes
  useEffect(() => {
    if (!collaboration.isConnected || !collaboration.currentRoom) return;

    const unsubscribers: (() => void)[] = [];

    // Element/data changed by remote user
    unsubscribers.push(
      collaboration.onDataChanged((message: DataChangeMessage) => {
        if (message.itemType !== "element") return;
        isApplyingRemoteChange.current = true;
        historyActions.setWithoutHistory((prev) => ({
          ...prev,
          elements: prev.elements.map((el) =>
            el.id === message.itemId
              ? { ...el, ...(message.newValue as Partial<AprtElement>) }
              : el,
          ),
        }));
        setTimeout(() => {
          isApplyingRemoteChange.current = false;
        }, 0);
      }),
    );

    // Element added by remote user
    unsubscribers.push(
      collaboration.onItemCreated((message: ItemCreatedMessage) => {
        if (message.itemType !== "element") return;
        isApplyingRemoteChange.current = true;
        historyActions.setWithoutHistory((prev) => ({
          ...prev,
          elements: [...prev.elements, message.item as AprtElement],
        }));
        setTimeout(() => {
          isApplyingRemoteChange.current = false;
        }, 0);
      }),
    );

    // Element deleted by remote user
    unsubscribers.push(
      collaboration.onItemDeleted((message: ItemDeletedMessage) => {
        if (message.itemType !== "element") return;
        isApplyingRemoteChange.current = true;
        historyActions.setWithoutHistory((prev) => ({
          ...prev,
          elements: prev.elements.filter((el) => el.id !== message.itemId),
        }));
        // Clear selection if deleted element was selected
        if (selectedElementIds.includes(message.itemId)) {
          setSelectedElementIds((prev) =>
            prev.filter((id) => id !== message.itemId),
          );
        }
        setTimeout(() => {
          isApplyingRemoteChange.current = false;
        }, 0);
      }),
    );

    // Page changes by remote user
    unsubscribers.push(
      collaboration.onDataChanged((message: DataChangeMessage) => {
        if (message.itemType !== "page") return;
        isApplyingRemoteChange.current = true;
        historyActions.setWithoutHistory((prev) => {
          switch (message.changeType) {
            case "added":
              return {
                ...prev,
                pages: [...prev.pages, message.newValue as AprtPage],
              };
            case "deleted":
              return {
                ...prev,
                pages: prev.pages.filter((p) => p.id !== message.itemId),
                elements: prev.elements.filter(
                  (e) => e.pageId !== message.itemId,
                ),
              };
            case "renamed":
              return {
                ...prev,
                pages: prev.pages.map((p) =>
                  p.id === message.itemId
                    ? { ...p, name: message.newValue as string }
                    : p,
                ),
              };
            case "reordered":
              return {
                ...prev,
                pages: message.newValue as AprtPage[],
              };
            case "settings":
              return {
                ...prev,
                pages: prev.pages.map((p) =>
                  p.id === message.itemId
                    ? { ...p, ...(message.newValue as Partial<AprtPage>) }
                    : p,
                ),
              };
            default:
              return prev;
          }
        });
        setTimeout(() => {
          isApplyingRemoteChange.current = false;
        }, 0);
      }),
    );

    // Template sync received - apply template directly without server reload
    unsubscribers.push(
      collaboration.onTemplateSync((message) => {
        console.log(
          `[Collaboration] Received TemplateSync, version ${message.version}, size: ${message.templateJson.length} bytes`,
        );

        // Only apply if the received version is newer
        if (message.version <= templateVersionRef.current) {
          console.log(
            `[Collaboration] Ignoring older template version ${message.version} (current: ${templateVersionRef.current})`,
          );
          return;
        }

        try {
          isApplyingRemoteChange.current = true;
          const receivedTemplate = JSON.parse(
            message.templateJson,
          ) as AprtTemplate;

          // Update version to received version
          templateVersionRef.current = message.version;

          // Apply template without adding to history (it's a sync, not a user action)
          historyActions.setWithoutHistory(() => receivedTemplate);

          // Show notification
          setSnackbar({
            open: true,
            message: "Template aggiornato da un altro utente",
            severity: "success",
          });

          // Also update the query cache so it stays in sync
          queryClient.setQueryData(["report-template", id], (old: unknown) => {
            if (!old) return old;
            return {
              ...(old as Record<string, unknown>),
              templateJson: message.templateJson,
            };
          });
        } catch (e) {
          console.error("[Collaboration] Error parsing received template:", e);
        } finally {
          setTimeout(() => {
            isApplyingRemoteChange.current = false;
          }, 0);
        }
      }),
    );

    // Legacy DataSaved handler (for backwards compatibility - will be removed)
    unsubscribers.push(
      collaboration.onDataSaved((message) => {
        console.log(
          "[Collaboration] Received DataSaved from:",
          message.savedBy,
          "(legacy - should use TemplateSync instead)",
        );
        // Only reload from server if we haven't received a TemplateSync
        // This is a fallback for older clients
      }),
    );

    // Sync requested - send current template to requester
    unsubscribers.push(
      collaboration.onSyncRequested((request) => {
        collaboration.sendSync(request.requesterId, JSON.stringify(template));
      }),
    );

    return () => {
      unsubscribers.forEach((unsub) => unsub());
    };
  }, [
    collaboration,
    historyActions,
    selectedElementIds,
    template,
    queryClient,
    id,
  ]);

  // Send selection changes to collaborators (send first selected element for compatibility)
  useEffect(() => {
    if (collaboration.isConnected && !isApplyingRemoteChange.current) {
      collaboration.sendSelectionChanged(selectedElementIds[0] || null);
    }
  }, [collaboration, selectedElementIds]);

  // Send view/page navigation to collaborators
  useEffect(() => {
    if (collaboration.isConnected && !isApplyingRemoteChange.current) {
      collaboration.sendViewChanged(currentPageId);
    }
  }, [collaboration, currentPageId]);

  // Load existing template
  const { data: existingTemplate, isLoading: isLoadingTemplate } = useQuery({
    queryKey: ["report-template", id],
    queryFn: () => reportTemplateService.getById(Number(id)),
    enabled: !!id,
  });

  // Load available datasets
  const { data: availableDatasets = [] } = useQuery({
    queryKey: ["available-datasets"],
    queryFn: () => reportGeneratorService.getAvailableDatasets(),
  });

  // Virtual datasets are now loaded via getAvailableDatasets API
  // This query is only for DatasetManagerDialog internal use
  useQuery({
    queryKey: ["virtual-datasets"],
    queryFn: () => virtualDatasetService.getAll(),
    enabled: datasetManagerDialog, // Only fetch when dialog is open
  });

  // Load schemas for selected datasets
  const schemaQueries = useQueries({
    queries: selectedDatasets.map((dataset) => ({
      queryKey: ["report-schema", dataset.id],
      queryFn: () => reportGeneratorService.getSchema(dataset.id),
      enabled: selectedDatasets.length > 0,
      staleTime: 60000,
    })),
  });

  const schemas = schemaQueries
    .filter((q) => q.isSuccess && q.data)
    .map((q) => q.data as DataSchemaDto);

  // Create a map of datasetId -> schema for PropertiesPanel
  const dataSchemaMap = schemas.reduce(
    (acc, schema) => {
      acc[schema.datasetId] = schema;
      return acc;
    },
    {} as Record<string, DataSchemaDto>,
  );

  // Load font families
  const {
    data: fontFamilies = ["Helvetica", "Times New Roman", "Courier", "Arial"],
  } = useQuery({
    queryKey: ["font-families"],
    queryFn: () => reportFontService.getFamilies(),
  });

  // Initialize template from loaded data
  useEffect(() => {
    if (existingTemplate) {
      try {
        const parsed = JSON.parse(
          existingTemplate.templateJson || "{}",
        ) as Partial<AprtTemplate>;

        // Merge with defaultTemplate to ensure all required fields exist
        const mergedTemplate: AprtTemplate = {
          ...defaultTemplate,
          ...parsed,
          meta: {
            ...defaultTemplate.meta,
            ...(parsed.meta || {}),
            margins: {
              ...defaultTemplate.meta.margins,
              ...(parsed.meta?.margins || {}),
            },
          },
          resources: {
            fonts: parsed.resources?.fonts || [],
            images: parsed.resources?.images || [],
          },
          dataSources: parsed.dataSources || {},
          sections: parsed.sections || [],
          pages:
            parsed.pages && parsed.pages.length > 0
              ? parsed.pages
              : [{ ...defaultPage }],
          elements: parsed.elements || [],
        };

        // Migrate legacy elements without pageId to first page
        const firstPageId = mergedTemplate.pages[0].id;
        mergedTemplate.elements.forEach((el) => {
          if (!el.pageId) {
            el.pageId = firstPageId;
          }
        });

        // Set current page to first page
        setCurrentPageId(firstPageId);

        // Reset history with the loaded template
        historyActions.reset(mergedTemplate);
        setTemplateInfo({
          nome: existingTemplate.nome,
          descrizione: existingTemplate.descrizione || "",
          categoria: existingTemplate.categoria,
        });

        // Restore selected datasets from template
        if (mergedTemplate.dataSources && availableDatasets.length > 0) {
          const datasetIds = Object.keys(mergedTemplate.dataSources);
          const datasets = availableDatasets.filter((d) =>
            datasetIds.includes(d.id),
          );
          setSelectedDatasets(datasets);
        }
      } catch (e) {
        console.error("Error parsing template:", e);
        // In case of error, keep defaultTemplate
      }
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [existingTemplate, availableDatasets]);

  // Save mutation
  const saveMutation = useMutation({
    mutationFn: async (data: {
      template: AprtTemplate;
      info: typeof templateInfo;
    }) => {
      // Update dataSources in template based on selected datasets
      const updatedTemplate = {
        ...data.template,
        dataSources: selectedDatasets.reduce(
          (acc, ds) => {
            acc[ds.id] = { type: "object" as const, schema: ds.id };
            return acc;
          },
          {} as Record<string, { type: "object"; schema: string }>,
        ),
      };

      const dto: Partial<ReportTemplateDto> = {
        nome: data.info.nome,
        descrizione: data.info.descrizione,
        categoria: data.info.categoria,
        templateJson: JSON.stringify(updatedTemplate),
        pageSize: data.template.meta.pageSize,
        orientation: data.template.meta.orientation,
        attivo: true,
      };

      if (id) {
        return reportTemplateService.update(Number(id), dto);
      } else {
        return reportTemplateService.create(dto);
      }
    },
    onSuccess: (result) => {
      queryClient.invalidateQueries({ queryKey: ["report-templates"] });
      setSnackbar({
        open: true,
        message: "Template salvato con successo",
        severity: "success",
      });
      setSaveDialog(false);
      // Mark current state as saved
      setLastSavedUndoCount(templateHistory.undoCount);

      // Broadcast template to collaborators (instant sync without server reload)
      if (collaboration.isConnected && collaboration.currentRoom) {
        // Update dataSources in template for broadcasting
        const updatedTemplateForSync = {
          ...template,
          dataSources: selectedDatasets.reduce(
            (acc, ds) => {
              acc[ds.id] = { type: "object" as const, schema: ds.id };
              return acc;
            },
            {} as Record<string, { type: "object"; schema: string }>,
          ),
        };

        // Increment version and broadcast
        templateVersionRef.current += 1;
        const templateJson = JSON.stringify(updatedTemplateForSync);
        console.log(
          `[AutoSave] Broadcasting template sync, version ${templateVersionRef.current}, size: ${templateJson.length} bytes`,
        );
        collaboration.broadcastTemplateSync(
          templateJson,
          templateVersionRef.current,
        );
      }

      if (isNew) {
        navigate(`/report-editor/${result.id}`, { replace: true });
      }
    },
    onError: (error) => {
      setSnackbar({
        open: true,
        message: `Errore nel salvataggio: ${error}`,
        severity: "error",
      });
    },
  });

  // Undo/Redo handlers using the history hook
  const handleUndo = useCallback(() => {
    historyActions.undo();
  }, [historyActions]);

  const handleRedo = useCallback(() => {
    historyActions.redo();
  }, [historyActions]);

  // Get selected element(s) - for single selection compatibility, use first selected
  const selectedElementId = selectedElementIds[0] || null;
  const selectedElement = selectedElementId
    ? template.elements.find((e) => e.id === selectedElementId)
    : null;
  const selectedElements = selectedElementIds
    .map((id) => template.elements.find((e) => e.id === id))
    .filter((e): e is AprtElement => e !== undefined);

  // Dataset management
  const handleAddDataset = useCallback((dataset: DatasetTypeDto) => {
    setSelectedDatasets((prev) => {
      if (prev.some((d) => d.id === dataset.id)) return prev;
      return [...prev, dataset];
    });
  }, []);

  const handleRemoveDataset = useCallback((datasetId: string) => {
    setSelectedDatasets((prev) => prev.filter((d) => d.id !== datasetId));
  }, []);

  // ============ PAGE MANAGEMENT HANDLERS ============

  // Get current page object
  const currentPage =
    template.pages.find((p) => p.id === currentPageId) || template.pages[0];
  const currentPageIndex = template.pages.findIndex(
    (p) => p.id === currentPageId,
  );

  // Get elements for current page only
  const currentPageElements = template.elements.filter(
    (e) =>
      e.pageId === currentPageId ||
      (!e.pageId && currentPageId === template.pages[0]?.id),
  );

  // Add new page
  const handleAddPage = useCallback(() => {
    const newPageId = `page-${uuidv4().slice(0, 8)}`;
    const newPage: AprtPage = {
      id: newPageId,
      name: `Pagina ${template.pages.length + 1}`,
    };

    historyActions.set((prev) => ({
      ...prev,
      pages: [...prev.pages, newPage],
    }));

    // Send to collaborators
    if (collaboration.isConnected && !isApplyingRemoteChange.current) {
      collaboration.sendDataChanged(newPageId, "page", "added", newPage);
    }

    // Switch to the new page
    setCurrentPageId(newPageId);
    setSelectedElementIds([]);
  }, [template.pages.length, historyActions, collaboration]);

  // Duplicate page with all its elements
  const handleDuplicatePage = useCallback(
    (pageId: string) => {
      const sourcePage = template.pages.find((p) => p.id === pageId);
      if (!sourcePage) return;

      const newPageId = `page-${uuidv4().slice(0, 8)}`;
      const newPage: AprtPage = {
        ...sourcePage,
        id: newPageId,
        name: `${sourcePage.name} (copia)`,
      };

      // Duplicate elements from source page
      const sourceElements = template.elements.filter(
        (e) => e.pageId === pageId,
      );
      const duplicatedElements: AprtElement[] = sourceElements.map((el) => ({
        ...el,
        id: uuidv4(),
        pageId: newPageId,
        name: el.name ? `${el.name}_copia` : undefined,
      }));

      historyActions.set((prev) => ({
        ...prev,
        pages: [...prev.pages, newPage],
        elements: [...prev.elements, ...duplicatedElements],
      }));

      // Switch to the new page
      setCurrentPageId(newPageId);
      setSelectedElementIds([]);
    },
    [template.pages, template.elements, historyActions],
  );

  // Delete page and its elements
  const handleDeletePage = useCallback(
    (pageId: string) => {
      // Don't allow deleting the last page
      if (template.pages.length <= 1) return;

      const pageIndex = template.pages.findIndex((p) => p.id === pageId);

      // Send to collaborators before deleting
      if (collaboration.isConnected && !isApplyingRemoteChange.current) {
        collaboration.sendDataChanged(pageId, "page", "deleted", null);
      }

      historyActions.set((prev) => ({
        ...prev,
        pages: prev.pages.filter((p) => p.id !== pageId),
        elements: prev.elements.filter((e) => e.pageId !== pageId),
      }));

      // Switch to adjacent page
      const newIndex = Math.min(pageIndex, template.pages.length - 2);
      const newCurrentPage = template.pages.filter((p) => p.id !== pageId)[
        newIndex
      ];
      if (newCurrentPage) {
        setCurrentPageId(newCurrentPage.id);
      }
      setSelectedElementIds([]);
    },
    [template.pages, historyActions, collaboration],
  );

  // Rename page
  const handleRenamePage = useCallback(
    (pageId: string, newName: string) => {
      historyActions.set((prev) => ({
        ...prev,
        pages: prev.pages.map((p) =>
          p.id === pageId ? { ...p, name: newName } : p,
        ),
      }));

      // Send to collaborators
      if (collaboration.isConnected && !isApplyingRemoteChange.current) {
        collaboration.sendDataChanged(pageId, "page", "renamed", newName);
      }
    },
    [historyActions, collaboration],
  );

  // Move page up or down
  const handleMovePage = useCallback(
    (pageId: string, direction: "up" | "down") => {
      const currentIndex = template.pages.findIndex((p) => p.id === pageId);
      if (currentIndex === -1) return;

      const newIndex = direction === "up" ? currentIndex - 1 : currentIndex + 1;
      if (newIndex < 0 || newIndex >= template.pages.length) return;

      historyActions.set((prev) => {
        const newPages = [...prev.pages];
        [newPages[currentIndex], newPages[newIndex]] = [
          newPages[newIndex],
          newPages[currentIndex],
        ];
        return { ...prev, pages: newPages };
      });
    },
    [template.pages, historyActions],
  );

  // Select page
  const handleSelectPage = useCallback((pageId: string) => {
    setCurrentPageId(pageId);
    setSelectedElementIds([]); // Clear selection when switching pages
  }, []);

  // Navigate to previous page
  const handlePrevPage = useCallback(() => {
    const currentIndex = template.pages.findIndex(
      (p) => p.id === currentPageId,
    );
    if (currentIndex > 0) {
      setCurrentPageId(template.pages[currentIndex - 1].id);
      setSelectedElementIds([]);
    }
  }, [template.pages, currentPageId]);

  // Navigate to next page
  const handleNextPage = useCallback(() => {
    const currentIndex = template.pages.findIndex(
      (p) => p.id === currentPageId,
    );
    if (currentIndex < template.pages.length - 1) {
      setCurrentPageId(template.pages[currentIndex + 1].id);
      setSelectedElementIds([]);
    }
  }, [template.pages, currentPageId]);

  // ============ END PAGE MANAGEMENT HANDLERS ============

  // Add new element
  const handleAddElement = useCallback(
    (type: ElementType) => {
      // For images, open the upload dialog instead of creating immediately
      if (type === "image") {
        setImageUploadDialog(true);
        return;
      }

      const newElement: AprtElement = {
        id: uuidv4(),
        type,
        pageId: currentPageId, // Assign to current page
        position: {
          x: 20,
          y: 20,
          width: type === "line" ? 100 : 80,
          height: type === "line" ? 1 : type === "table" ? 60 : 20,
        },
        style: { ...defaultStyle },
        content:
          type === "text"
            ? { type: "static", value: "Nuovo testo" }
            : undefined,
        visible: true,
        locked: false,
        name: `${type}_${Date.now()}`,
        columns:
          type === "table"
            ? [
                {
                  field: "campo1",
                  header: "Colonna 1",
                  width: 50,
                  align: "left",
                },
                {
                  field: "campo2",
                  header: "Colonna 2",
                  width: 50,
                  align: "left",
                },
              ]
            : undefined,
      };

      historyActions.set((prev) => ({
        ...prev,
        elements: [...prev.elements, newElement],
      }));
      setSelectedElementIds([newElement.id]);

      // Send to collaborators
      if (collaboration.isConnected && !isApplyingRemoteChange.current) {
        collaboration.sendItemCreated(newElement.id, "element", newElement);
      }

      // On mobile, open properties panel after adding element
      if (isMobile) {
        setMobilePanel("properties");
      }
    },
    [historyActions, currentPageId, isMobile, collaboration],
  );

  // Update element without history (for continuous updates like dragging)
  const handleUpdateElementWithoutHistory = useCallback(
    (elementId: string, updates: Partial<AprtElement>) => {
      historyActions.setWithoutHistory((prev) => ({
        ...prev,
        elements: prev.elements.map((el) =>
          el.id === elementId ? { ...el, ...updates } : el,
        ),
      }));
    },
    [historyActions],
  );

  // Update element with history
  const handleUpdateElement = useCallback(
    (elementId: string, updates: Partial<AprtElement>) => {
      historyActions.set((prev) => ({
        ...prev,
        elements: prev.elements.map((el) =>
          el.id === elementId ? { ...el, ...updates } : el,
        ),
      }));

      // Send to collaborators
      if (collaboration.isConnected && !isApplyingRemoteChange.current) {
        collaboration.sendDataChanged(elementId, "element", "full", updates);
      }
    },
    [historyActions, collaboration],
  );

  // Handle image selection from dialog
  const handleImageSelected = useCallback(
    (imageData: ImageData) => {
      // Calculate appropriate size based on original dimensions
      // Max 100mm width, proportional height
      const maxWidth = 100; // mm
      const aspectRatio = imageData.originalWidth / imageData.originalHeight;
      let width = Math.min(maxWidth, imageData.originalWidth / 3.78); // rough px to mm
      let height = width / aspectRatio;

      // Ensure minimum size
      if (width < 20) width = 20;
      if (height < 20) height = 20;

      // Check if we're replacing an existing image element
      if (selectedElementId) {
        const existingElement = template.elements.find(
          (e) => e.id === selectedElementId && e.type === "image",
        );
        if (existingElement) {
          // Update existing image element
          handleUpdateElement(selectedElementId, {
            imageSettings: {
              ...defaultImageSettings,
              ...existingElement.imageSettings,
              src: imageData.src,
              originalWidth: imageData.originalWidth,
              originalHeight: imageData.originalHeight,
            },
          });
          return;
        }
      }

      // Create new image element
      const newElement: AprtElement = {
        id: uuidv4(),
        type: "image",
        pageId: currentPageId, // Assign to current page
        position: {
          x: 20,
          y: 20,
          width: Math.round(width),
          height: Math.round(height),
        },
        style: { ...defaultStyle },
        imageSettings: {
          ...defaultImageSettings,
          src: imageData.src,
          originalWidth: imageData.originalWidth,
          originalHeight: imageData.originalHeight,
        },
        visible: true,
        locked: false,
        name: imageData.fileName || `image_${Date.now()}`,
      };

      historyActions.set((prev) => ({
        ...prev,
        elements: [...prev.elements, newElement],
      }));
      setSelectedElementIds([newElement.id]);
    },
    [
      selectedElementId,
      template.elements,
      handleUpdateElement,
      historyActions,
      currentPageId,
    ],
  );

  // Update selected element (with history)
  const handleUpdateSelectedElement = useCallback(
    (updates: Partial<AprtElement>) => {
      if (!selectedElementId) return;
      handleUpdateElement(selectedElementId, updates);
    },
    [selectedElementId, handleUpdateElement],
  );

  // Delete element
  const handleDeleteElement = useCallback(() => {
    if (!selectedElementId) return;

    // Send to collaborators before deleting
    if (collaboration.isConnected && !isApplyingRemoteChange.current) {
      collaboration.sendItemDeleted(selectedElementId, "element");
    }

    historyActions.set((prev) => ({
      ...prev,
      elements: prev.elements.filter((el) => el.id !== selectedElementId),
    }));
    setSelectedElementIds([]);
  }, [selectedElementId, historyActions, collaboration]);

  // Copy element
  const handleCopyElement = useCallback(() => {
    if (!selectedElement) return;
    const copy: AprtElement = {
      ...selectedElement,
      id: uuidv4(),
      name: `${selectedElement.name}_copia`,
      position: {
        ...selectedElement.position,
        x: selectedElement.position.x + 10,
        y: selectedElement.position.y + 10,
      },
    };
    historyActions.set((prev) => ({
      ...prev,
      elements: [...prev.elements, copy],
    }));
    setSelectedElementIds([copy.id]);
  }, [selectedElement, historyActions]);

  // Toggle lock
  const handleToggleLock = useCallback(() => {
    if (!selectedElementId) return;
    handleUpdateElement(selectedElementId, {
      locked: !selectedElement?.locked,
    });
  }, [selectedElementId, selectedElement, handleUpdateElement]);

  // Update page settings
  const handleUpdatePage = useCallback(
    (updates: {
      pageSize?: PageSize;
      orientation?: PageOrientation;
      margins?: AprtMargins;
    }) => {
      historyActions.set((prev) => ({
        ...prev,
        meta: {
          ...prev.meta,
          ...(updates.pageSize && { pageSize: updates.pageSize }),
          ...(updates.orientation && { orientation: updates.orientation }),
          ...(updates.margins && { margins: updates.margins }),
        },
      }));
    },
    [historyActions],
  );

  // Insert binding into selected text element
  const handleInsertBinding = useCallback(
    (binding: string) => {
      if (!selectedElement || selectedElement.type !== "text") return;

      const currentValue =
        selectedElement.content?.value ||
        selectedElement.content?.expression ||
        "";
      const newContent = {
        ...selectedElement.content,
        type: "binding" as const,
        expression: currentValue + binding,
      };
      handleUpdateElement(selectedElement.id, { content: newContent });
    },
    [selectedElement, handleUpdateElement],
  );

  // ============ CONTEXT MENU HANDLERS ============

  // Handle context menu event from canvas
  const handleContextMenu = useCallback((event: ContextMenuEvent) => {
    if (event.elementId) {
      setSelectedElementIds(event.elementId ? [event.elementId] : []);
    }
    setContextMenu({
      open: true,
      position: event.position,
    });
  }, []);

  const closeContextMenu = useCallback(() => {
    setContextMenu({ open: false, position: null });
  }, []);

  // Cut element (copy + delete)
  const handleCut = useCallback(() => {
    if (!selectedElement) return;
    setClipboard({ ...selectedElement });
    handleDeleteElement();
  }, [selectedElement, handleDeleteElement]);

  // Copy to clipboard
  const handleCopy = useCallback(() => {
    if (!selectedElement) return;
    setClipboard({ ...selectedElement });
    setSnackbar({
      open: true,
      message: "Elemento copiato",
      severity: "success",
    });
  }, [selectedElement]);

  // Paste from clipboard
  const handlePaste = useCallback(() => {
    if (!clipboard) return;
    const pastedElement: AprtElement = {
      ...clipboard,
      id: uuidv4(),
      name: `${clipboard.name}_incollato`,
      position: {
        ...clipboard.position,
        x: clipboard.position.x + 10,
        y: clipboard.position.y + 10,
      },
    };
    historyActions.set((prev) => ({
      ...prev,
      elements: [...prev.elements, pastedElement],
    }));
    setSelectedElementIds([pastedElement.id]);
  }, [clipboard, historyActions]);

  // Duplicate element
  const handleDuplicate = useCallback(() => {
    handleCopyElement();
  }, [handleCopyElement]);

  // Layer operations
  const handleBringToFront = useCallback(() => {
    if (!selectedElementId) return;
    historyActions.set((prev) => {
      const elements = [...prev.elements];
      const idx = elements.findIndex((e) => e.id === selectedElementId);
      if (idx === -1 || idx === elements.length - 1) return prev;
      const [element] = elements.splice(idx, 1);
      elements.push(element);
      return { ...prev, elements };
    });
  }, [selectedElementId, historyActions]);

  const handleSendToBack = useCallback(() => {
    if (!selectedElementId) return;
    historyActions.set((prev) => {
      const elements = [...prev.elements];
      const idx = elements.findIndex((e) => e.id === selectedElementId);
      if (idx === -1 || idx === 0) return prev;
      const [element] = elements.splice(idx, 1);
      elements.unshift(element);
      return { ...prev, elements };
    });
  }, [selectedElementId, historyActions]);

  const handleBringForward = useCallback(() => {
    if (!selectedElementId) return;
    historyActions.set((prev) => {
      const elements = [...prev.elements];
      const idx = elements.findIndex((e) => e.id === selectedElementId);
      if (idx === -1 || idx === elements.length - 1) return prev;
      [elements[idx], elements[idx + 1]] = [elements[idx + 1], elements[idx]];
      return { ...prev, elements };
    });
  }, [selectedElementId, historyActions]);

  const handleSendBackward = useCallback(() => {
    if (!selectedElementId) return;
    historyActions.set((prev) => {
      const elements = [...prev.elements];
      const idx = elements.findIndex((e) => e.id === selectedElementId);
      if (idx === -1 || idx === 0) return prev;
      [elements[idx], elements[idx - 1]] = [elements[idx - 1], elements[idx]];
      return { ...prev, elements };
    });
  }, [selectedElementId, historyActions]);

  // Get page dimensions for alignment
  const getPageDimensionsMm = useCallback(() => {
    const sizes: Record<string, { width: number; height: number }> = {
      A4: { width: 210, height: 297 },
      A3: { width: 297, height: 420 },
      Letter: { width: 216, height: 279 },
      Legal: { width: 216, height: 356 },
    };
    const size = sizes[template.meta.pageSize] || sizes.A4;
    return template.meta.orientation === "landscape"
      ? { width: size.height, height: size.width }
      : size;
  }, [template.meta.pageSize, template.meta.orientation]);

  // Alignment operations
  const handleAlignLeft = useCallback(() => {
    if (!selectedElement) return;
    handleUpdateElement(selectedElementId!, {
      position: {
        ...selectedElement.position,
        x: template.meta.margins.left,
      },
    });
  }, [
    selectedElement,
    selectedElementId,
    template.meta.margins.left,
    handleUpdateElement,
  ]);

  const handleAlignCenter = useCallback(() => {
    if (!selectedElement) return;
    const pageDims = getPageDimensionsMm();
    const centerX = (pageDims.width - selectedElement.position.width) / 2;
    handleUpdateElement(selectedElementId!, {
      position: {
        ...selectedElement.position,
        x: centerX,
      },
    });
  }, [
    selectedElement,
    selectedElementId,
    getPageDimensionsMm,
    handleUpdateElement,
  ]);

  const handleAlignRight = useCallback(() => {
    if (!selectedElement) return;
    const pageDims = getPageDimensionsMm();
    handleUpdateElement(selectedElementId!, {
      position: {
        ...selectedElement.position,
        x:
          pageDims.width -
          template.meta.margins.right -
          selectedElement.position.width,
      },
    });
  }, [
    selectedElement,
    selectedElementId,
    getPageDimensionsMm,
    template.meta.margins.right,
    handleUpdateElement,
  ]);

  const handleAlignTop = useCallback(() => {
    if (!selectedElement) return;
    handleUpdateElement(selectedElementId!, {
      position: {
        ...selectedElement.position,
        y: template.meta.margins.top,
      },
    });
  }, [
    selectedElement,
    selectedElementId,
    template.meta.margins.top,
    handleUpdateElement,
  ]);

  const handleAlignMiddle = useCallback(() => {
    if (!selectedElement) return;
    const pageDims = getPageDimensionsMm();
    const centerY = (pageDims.height - selectedElement.position.height) / 2;
    handleUpdateElement(selectedElementId!, {
      position: {
        ...selectedElement.position,
        y: centerY,
      },
    });
  }, [
    selectedElement,
    selectedElementId,
    getPageDimensionsMm,
    handleUpdateElement,
  ]);

  const handleAlignBottom = useCallback(() => {
    if (!selectedElement) return;
    const pageDims = getPageDimensionsMm();
    handleUpdateElement(selectedElementId!, {
      position: {
        ...selectedElement.position,
        y:
          pageDims.height -
          template.meta.margins.bottom -
          selectedElement.position.height,
      },
    });
  }, [
    selectedElement,
    selectedElementId,
    getPageDimensionsMm,
    template.meta.margins.bottom,
    handleUpdateElement,
  ]);

  const handleCenterOnPage = useCallback(() => {
    if (!selectedElement) return;
    const pageDims = getPageDimensionsMm();
    handleUpdateElement(selectedElementId!, {
      position: {
        ...selectedElement.position,
        x: (pageDims.width - selectedElement.position.width) / 2,
        y: (pageDims.height - selectedElement.position.height) / 2,
      },
    });
  }, [
    selectedElement,
    selectedElementId,
    getPageDimensionsMm,
    handleUpdateElement,
  ]);

  // Transform operations
  const handleRotateLeft = useCallback(() => {
    if (!selectedElement) return;
    handleUpdateElement(selectedElementId!, {
      position: {
        ...selectedElement.position,
        rotation: ((selectedElement.position.rotation || 0) - 90) % 360,
      },
    });
  }, [selectedElement, selectedElementId, handleUpdateElement]);

  const handleRotateRight = useCallback(() => {
    if (!selectedElement) return;
    handleUpdateElement(selectedElementId!, {
      position: {
        ...selectedElement.position,
        rotation: ((selectedElement.position.rotation || 0) + 90) % 360,
      },
    });
  }, [selectedElement, selectedElementId, handleUpdateElement]);

  const handleFlipHorizontal = useCallback(() => {
    if (!selectedElement || selectedElement.type !== "image") return;
    handleUpdateElement(selectedElementId!, {
      imageSettings: {
        ...defaultImageSettings,
        ...selectedElement.imageSettings,
        flipHorizontal: !selectedElement.imageSettings?.flipHorizontal,
      },
    });
  }, [selectedElement, selectedElementId, handleUpdateElement]);

  const handleFlipVertical = useCallback(() => {
    if (!selectedElement || selectedElement.type !== "image") return;
    handleUpdateElement(selectedElementId!, {
      imageSettings: {
        ...defaultImageSettings,
        ...selectedElement.imageSettings,
        flipVertical: !selectedElement.imageSettings?.flipVertical,
      },
    });
  }, [selectedElement, selectedElementId, handleUpdateElement]);

  // Group operations (placeholder - tables are treated as groups)
  const handleGroup = useCallback(() => {
    setSnackbar({
      open: true,
      message: "Raggruppamento non ancora implementato",
      severity: "error",
    });
  }, []);

  const handleUngroup = useCallback(() => {
    setSnackbar({
      open: true,
      message: "Separazione non ancora implementata",
      severity: "error",
    });
  }, []);

  // Selection operations
  const handleSelectAll = useCallback(() => {
    // Select all elements on the current page
    const pageElementIds = currentPageElements.map((e) => e.id);
    if (pageElementIds.length > 0) {
      setSelectedElementIds(pageElementIds);
    }
  }, [currentPageElements]);

  const handleDeselectAll = useCallback(() => {
    setSelectedElementIds([]);
  }, []);

  // Toggle visibility
  const handleToggleVisibility = useCallback(() => {
    if (!selectedElement) return;
    handleUpdateElement(selectedElementId!, {
      visible: !selectedElement.visible,
    });
  }, [selectedElement, selectedElementId, handleUpdateElement]);

  // Unlock element
  const handleUnlock = useCallback(() => {
    if (!selectedElementId) return;
    handleUpdateElement(selectedElementId, { locked: false });
  }, [selectedElementId, handleUpdateElement]);

  // Edit text (focus on element for editing)
  const handleEditText = useCallback(() => {
    // This would need canvas ref to trigger text editing
    // For now, just select the element
    setSnackbar({
      open: true,
      message: "Fai doppio click sul testo per modificarlo",
      severity: "success",
    });
  }, []);

  // Replace image
  const handleReplaceImage = useCallback(() => {
    if (selectedElement?.type === "image") {
      setImageUploadDialog(true);
    }
  }, [selectedElement]);

  // Fit to content (for text elements)
  const handleFitToContent = useCallback(() => {
    // This would need to calculate text dimensions
    setSnackbar({
      open: true,
      message: "Adatta al contenuto non ancora implementato",
      severity: "error",
    });
  }, []);

  // ============ END CONTEXT MENU HANDLERS ============

  // Save template
  const handleSave = useCallback(() => {
    if (isNew) {
      setSaveDialog(true);
    } else {
      saveMutation.mutate({ template, info: templateInfo });
    }
  }, [isNew, template, templateInfo, saveMutation]);

  // Preview PDF
  const handlePreview = useCallback(() => {
    if (selectedDatasets.length === 0) {
      setSnackbar({
        open: true,
        message: "Seleziona almeno un dataset per l'anteprima",
        severity: "error",
      });
      return;
    }
    setPreviewDialog(true);
  }, [selectedDatasets]);

  // Generate preview with selected data
  const handleGeneratePreview = useCallback(
    async (dataSources: DataSourceSelection[]) => {
      try {
        setIsGeneratingPreview(true);

        // Save template first if new
        if (isNew) {
          setSnackbar({
            open: true,
            message: "Salva il template prima di visualizzare l'anteprima",
            severity: "error",
          });
          setPreviewDialog(false);
          setIsGeneratingPreview(false);
          return;
        }

        const blob = await reportGeneratorService.preview({
          templateId: Number(id),
          dataSources,
        });
        openBlobInNewTab(blob);
        setPreviewDialog(false);
      } catch (error) {
        setSnackbar({
          open: true,
          message: `Errore nella generazione dell'anteprima: ${error}`,
          severity: "error",
        });
      } finally {
        setIsGeneratingPreview(false);
      }
    },
    [id, isNew],
  );

  // Keyboard shortcuts
  useEffect(() => {
    const handleKeyDown = (e: KeyboardEvent) => {
      // Don't handle shortcuts when typing in input fields
      const target = e.target as HTMLElement;
      const isInputField =
        target.tagName === "INPUT" ||
        target.tagName === "TEXTAREA" ||
        target.isContentEditable;

      // Don't handle shortcuts when editing text in canvas
      const isCanvasTextEditing = canvasRef.current?.isTextEditing() ?? false;

      // Allow browser defaults for input fields and text editing
      if (isInputField || isCanvasTextEditing) {
        return;
      }

      const hasCtrl = e.ctrlKey || e.metaKey;
      const hasShift = e.shiftKey;

      // Handle Ctrl/Cmd shortcuts
      if (hasCtrl) {
        switch (e.key.toLowerCase()) {
          // Undo: Ctrl+Z
          case "z":
            if (!hasShift) {
              e.preventDefault();
              handleUndo();
            }
            break;

          // Redo: Ctrl+Y or Ctrl+Shift+Z
          case "y":
            e.preventDefault();
            handleRedo();
            break;

          // Save: Ctrl+S
          case "s":
            e.preventDefault();
            handleSave();
            break;

          // Cut: Ctrl+X
          case "x":
            if (selectedElementId) {
              e.preventDefault();
              handleCut();
            }
            break;

          // Copy: Ctrl+C
          case "c":
            if (selectedElementId) {
              e.preventDefault();
              handleCopy();
            }
            break;

          // Paste: Ctrl+V
          case "v":
            if (clipboard) {
              e.preventDefault();
              handlePaste();
            }
            break;

          // Duplicate: Ctrl+D
          case "d":
            if (selectedElementId) {
              e.preventDefault();
              handleDuplicate();
            }
            break;

          // Select All: Ctrl+A
          case "a":
            e.preventDefault();
            handleSelectAll();
            break;

          // Lock/Unlock: Ctrl+L
          case "l":
            if (selectedElementId) {
              e.preventDefault();
              handleToggleLock();
            }
            break;

          // Group: Ctrl+G / Ungroup: Ctrl+Shift+G
          case "g":
            if (selectedElementId) {
              e.preventDefault();
              if (hasShift) {
                handleUngroup();
              } else {
                handleGroup();
              }
            }
            break;

          // Layer ordering with brackets
          // Bring Forward: Ctrl+] / Bring to Front: Ctrl+Shift+]
          case "]":
            if (selectedElementId) {
              e.preventDefault();
              if (hasShift) {
                handleBringToFront();
              } else {
                handleBringForward();
              }
            }
            break;

          // Send Backward: Ctrl+[ / Send to Back: Ctrl+Shift+[
          case "[":
            if (selectedElementId) {
              e.preventDefault();
              if (hasShift) {
                handleSendToBack();
              } else {
                handleSendBackward();
              }
            }
            break;
        }
      }

      // Non-Ctrl shortcuts
      if (!hasCtrl) {
        switch (e.key) {
          // Delete element
          case "Delete":
          case "Backspace":
            if (selectedElementId && !selectedElement?.locked) {
              e.preventDefault();
              handleDeleteElement();
            }
            break;

          // Escape to deselect
          case "Escape":
            e.preventDefault();
            handleDeselectAll();
            break;

          // Page navigation
          case "PageUp":
            e.preventDefault();
            handlePrevPage();
            break;

          case "PageDown":
            e.preventDefault();
            handleNextPage();
            break;
        }
      }
    };

    window.addEventListener("keydown", handleKeyDown);
    return () => window.removeEventListener("keydown", handleKeyDown);
  }, [
    handleUndo,
    handleRedo,
    handleSave,
    handleCut,
    handleCopy,
    handlePaste,
    handleDuplicate,
    handleSelectAll,
    handleDeselectAll,
    handleToggleLock,
    handleGroup,
    handleUngroup,
    handleBringToFront,
    handleBringForward,
    handleSendToBack,
    handleSendBackward,
    handleDeleteElement,
    handlePrevPage,
    handleNextPage,
    selectedElementId,
    selectedElement,
    clipboard,
  ]);

  // Auto-save: simple debounced save on every template change
  const autoSaveTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
  const saveMutationRef = useRef(saveMutation);
  saveMutationRef.current = saveMutation;
  const templateForSaveRef = useRef(template);
  templateForSaveRef.current = template;
  const templateInfoForSaveRef = useRef(templateInfo);
  templateInfoForSaveRef.current = templateInfo;

  useEffect(() => {
    // Skip if disabled or new template
    if (!autoSaveEnabled || isNew) {
      return;
    }

    // Skip if no unsaved changes
    if (!hasUnsavedChanges) {
      return;
    }

    // Clear previous timeout (debounce)
    if (autoSaveTimeoutRef.current) {
      clearTimeout(autoSaveTimeoutRef.current);
    }

    // Save after 500ms debounce
    autoSaveTimeoutRef.current = setTimeout(() => {
      // Check if not already saving at the moment of execution
      if (!saveMutationRef.current.isPending) {
        console.log("[AutoSave] Saving...");
        saveMutationRef.current.mutate({
          template: templateForSaveRef.current,
          info: templateInfoForSaveRef.current,
        });
      }
    }, 500);

    return () => {
      if (autoSaveTimeoutRef.current) {
        clearTimeout(autoSaveTimeoutRef.current);
      }
    };
  }, [autoSaveEnabled, isNew, hasUnsavedChanges, templateHistory.undoCount]);

  if (isLoadingTemplate && id) {
    return (
      <Box
        display="flex"
        justifyContent="center"
        alignItems="center"
        minHeight="400px"
      >
        <CircularProgress />
      </Box>
    );
  }

  // Render panels based on screen size
  // embedded=true when used inside CollapsiblePanel (removes internal borders/headers)
  const renderPageNavigator = (embedded = false) => (
    <PageNavigator
      pages={template.pages}
      elements={template.elements}
      currentPageId={currentPageId}
      onSelectPage={handleSelectPage}
      onAddPage={handleAddPage}
      onDuplicatePage={handleDuplicatePage}
      onDeletePage={handleDeletePage}
      onRenamePage={handleRenamePage}
      onMovePage={handleMovePage}
      embedded={embedded}
    />
  );

  const renderDataBindingPanel = (embedded = false) => (
    <DataBindingPanel
      schemas={schemas}
      selectedDatasets={selectedDatasets}
      onInsertBinding={handleInsertBinding}
      onRemoveDataset={handleRemoveDataset}
      embedded={embedded}
    />
  );

  const renderPropertiesPanel = (embedded = false) => (
    <PropertiesPanel
      element={selectedElement || null}
      onUpdateElement={handleUpdateSelectedElement}
      pageSize={(currentPage?.pageSize as PageSize) || template.meta.pageSize}
      orientation={
        (currentPage?.orientation as PageOrientation) ||
        template.meta.orientation
      }
      margins={currentPage?.margins || template.meta.margins}
      onUpdatePage={handleUpdatePage}
      fontFamilies={fontFamilies}
      availableDatasets={availableDatasets}
      dataSchemas={dataSchemaMap}
      onOpenImageUpload={() => setImageUploadDialog(true)}
      // Page-specific props
      currentPage={currentPage}
      onUpdateCurrentPage={(updates) => {
        if (!currentPage) return;
        historyActions.set((prev) => ({
          ...prev,
          pages: prev.pages.map((p) =>
            p.id === currentPage.id ? { ...p, ...updates } : p,
          ),
        }));
      }}
      embedded={embedded}
    />
  );

  // Mobile drawer content
  const renderMobileDrawerContent = () => {
    switch (mobilePanel) {
      case "pages":
        return renderPageNavigator();
      case "data":
        return renderDataBindingPanel();
      case "properties":
        return renderPropertiesPanel();
      default:
        return null;
    }
  };

  const getMobilePanelTitle = () => {
    switch (mobilePanel) {
      case "pages":
        return "Pagine";
      case "data":
        return "Campi Dati";
      case "properties":
        return "Proprietà";
      default:
        return "";
    }
  };

  return (
    <Box
      sx={{
        display: "flex",
        flexDirection: "column",
        flex: 1,
        width: "100%",
        minHeight: 0, // Important: allows flex container to shrink
        overflow: "hidden",
      }}
    >
      {/* Dataset Selector - hide on mobile, show in compact mode on tablet */}
      {!isMobile && (
        <DatasetSelector
          availableDatasets={availableDatasets}
          selectedDatasets={selectedDatasets}
          onAddDataset={handleAddDataset}
          onRemoveDataset={handleRemoveDataset}
          onOpenDatasetManager={() => setDatasetManagerDialog(true)}
        />
      )}

      {/* Toolbar */}
      <EditorToolbar
        onAddElement={handleAddElement}
        onDeleteElement={handleDeleteElement}
        onCopyElement={handleCopyElement}
        onToggleLock={handleToggleLock}
        zoom={zoom}
        onZoomChange={setZoom}
        showGrid={showGrid}
        onToggleGrid={() => setShowGrid(!showGrid)}
        snapOptions={snapOptions}
        onSnapOptionsChange={setSnapOptions}
        canUndo={templateHistory.canUndo}
        canRedo={templateHistory.canRedo}
        onUndo={handleUndo}
        onRedo={handleRedo}
        onSave={handleSave}
        onPreview={handlePreview}
        hasSelection={!!selectedElementId}
        isLocked={selectedElement?.locked || false}
        isSaving={saveMutation.isPending}
        currentPageIndex={currentPageIndex}
        totalPages={template.pages.length}
        currentPageName={currentPage?.name || "Pagina 1"}
        onPrevPage={handlePrevPage}
        onNextPage={handleNextPage}
        hasUnsavedChanges={hasUnsavedChanges}
        // Auto-save props
        autoSaveEnabled={autoSaveEnabled}
        onAutoSaveToggle={setAutoSaveEnabled}
      />

      {/* Main Editor Area */}
      <Box sx={{ display: "flex", flex: 1, overflow: "hidden" }}>
        {/* Left Sidebar - Panels on left side */}
        {!isMobile &&
          (() => {
            const leftPanels = panelLayout.getPanelsForPosition("left");
            return (
              <SidebarDropZone
                position="left"
                width={panelLayout.getSidebarWidth("left")}
                onWidthChange={(w) => panelLayout.setSidebarWidth("left", w)}
                onPanelDrop={handlePanelDrop}
                panelIds={leftPanels.map((p) => p.id)}
              >
                {leftPanels.map((panelState, index) => {
                  const isLast = index === leftPanels.length - 1;
                  if (panelState.id === "pages") {
                    return (
                      <ResizablePanel
                        key={panelState.id}
                        id={panelState.id}
                        title="Pagine"
                        icon={<LayersIcon />}
                        position="left"
                        flex={panelState.flex}
                        collapsed={panelState.collapsed}
                        onFlexChange={(f) =>
                          panelLayout.setPanelFlex(panelState.id, f)
                        }
                        onToggleCollapse={() =>
                          panelLayout.togglePanelCollapse(panelState.id)
                        }
                        badge={template.pages.length}
                        isLast={isLast}
                      >
                        {renderPageNavigator(true)}
                      </ResizablePanel>
                    );
                  }
                  if (panelState.id === "data") {
                    return (
                      <ResizablePanel
                        key={panelState.id}
                        id={panelState.id}
                        title="Campi Dati"
                        icon={<DataIcon />}
                        position="left"
                        flex={panelState.flex}
                        collapsed={panelState.collapsed}
                        onFlexChange={(f) =>
                          panelLayout.setPanelFlex(panelState.id, f)
                        }
                        onToggleCollapse={() =>
                          panelLayout.togglePanelCollapse(panelState.id)
                        }
                        badge={
                          selectedDatasets.length > 0
                            ? selectedDatasets.length
                            : undefined
                        }
                        isLast={isLast}
                      >
                        {renderDataBindingPanel(true)}
                      </ResizablePanel>
                    );
                  }
                  if (panelState.id === "properties") {
                    return (
                      <ResizablePanel
                        key={panelState.id}
                        id={panelState.id}
                        title="Proprietà"
                        icon={<SettingsIcon />}
                        position="left"
                        flex={panelState.flex}
                        collapsed={panelState.collapsed}
                        onFlexChange={(f) =>
                          panelLayout.setPanelFlex(panelState.id, f)
                        }
                        onToggleCollapse={() =>
                          panelLayout.togglePanelCollapse(panelState.id)
                        }
                        isLast={isLast}
                      >
                        {renderPropertiesPanel(true)}
                      </ResizablePanel>
                    );
                  }
                  return null;
                })}
              </SidebarDropZone>
            );
          })()}

        {/* Center Area - Canvas Container (flex: 1 to take remaining space, centers the canvas) */}
        <Box
          sx={{
            flex: 1,
            display: "flex",
            flexDirection: "column",
            alignItems: "center",
            justifyContent: "flex-start",
            overflow: "auto",
            bgcolor: (theme) =>
              theme.palette.mode === "dark" ? "#1a1a1a" : "#e0e0e0",
            position: "relative",
          }}
        >
          {/* Canvas - show only elements for current page */}
          <EditorCanvas
            ref={canvasRef}
            template={{
              ...template,
              elements: currentPageElements,
              // Use current page settings if available, otherwise template defaults
              meta: {
                ...template.meta,
                pageSize:
                  (currentPage?.pageSize as PageSize) || template.meta.pageSize,
                orientation:
                  (currentPage?.orientation as PageOrientation) ||
                  template.meta.orientation,
                margins: currentPage?.margins || template.meta.margins,
              },
            }}
            selectedElementIds={selectedElementIds}
            onSelectElement={(ids) => {
              setSelectedElementIds(ids);
              // On mobile, auto-open properties when selecting element
              if (isMobile && ids.length > 0) {
                setMobilePanel("properties");
              }
            }}
            onUpdateElement={handleUpdateElementWithoutHistory}
            onUpdateElementComplete={historyActions.commit}
            zoom={zoom}
            showGrid={showGrid}
            gridSize={gridSize}
            snapOptions={snapOptions}
            onContextMenu={handleContextMenu}
          />
        </Box>

        {/* Right Sidebar - Panels on right side */}
        {!isMobile &&
          (() => {
            const rightPanels = panelLayout.getPanelsForPosition("right");
            return (
              <SidebarDropZone
                position="right"
                width={panelLayout.getSidebarWidth("right")}
                onWidthChange={(w) => panelLayout.setSidebarWidth("right", w)}
                onPanelDrop={handlePanelDrop}
                panelIds={rightPanels.map((p) => p.id)}
              >
                {rightPanels.map((panelState, index) => {
                  const isLast = index === rightPanels.length - 1;
                  if (panelState.id === "pages") {
                    return (
                      <ResizablePanel
                        key={panelState.id}
                        id={panelState.id}
                        title="Pagine"
                        icon={<LayersIcon />}
                        position={panelState.position}
                        flex={panelState.flex}
                        collapsed={panelState.collapsed}
                        onFlexChange={(f) =>
                          panelLayout.setPanelFlex(panelState.id, f)
                        }
                        onToggleCollapse={() =>
                          panelLayout.togglePanelCollapse(panelState.id)
                        }
                        badge={template.pages.length}
                        isLast={isLast}
                      >
                        {renderPageNavigator(true)}
                      </ResizablePanel>
                    );
                  }
                  if (panelState.id === "data") {
                    return (
                      <ResizablePanel
                        key={panelState.id}
                        id={panelState.id}
                        title="Campi Dati"
                        icon={<DataIcon />}
                        position={panelState.position}
                        flex={panelState.flex}
                        collapsed={panelState.collapsed}
                        onFlexChange={(f) =>
                          panelLayout.setPanelFlex(panelState.id, f)
                        }
                        onToggleCollapse={() =>
                          panelLayout.togglePanelCollapse(panelState.id)
                        }
                        badge={
                          selectedDatasets.length > 0
                            ? selectedDatasets.length
                            : undefined
                        }
                        isLast={isLast}
                      >
                        {renderDataBindingPanel(true)}
                      </ResizablePanel>
                    );
                  }
                  if (panelState.id === "properties") {
                    return (
                      <ResizablePanel
                        key={panelState.id}
                        id={panelState.id}
                        title="Proprietà"
                        icon={<SettingsIcon />}
                        position={panelState.position}
                        flex={panelState.flex}
                        collapsed={panelState.collapsed}
                        onFlexChange={(f) =>
                          panelLayout.setPanelFlex(panelState.id, f)
                        }
                        onToggleCollapse={() =>
                          panelLayout.togglePanelCollapse(panelState.id)
                        }
                        isLast={isLast}
                      >
                        {renderPropertiesPanel(true)}
                      </ResizablePanel>
                    );
                  }
                  return null;
                })}
              </SidebarDropZone>
            );
          })()}
      </Box>

      {/* Mobile Bottom Navigation */}
      {isMobile && (
        <Paper
          sx={{
            position: "fixed",
            bottom: 0,
            left: 0,
            right: 0,
            zIndex: 1100,
            borderTop: 1,
            borderColor: "divider",
          }}
          elevation={3}
        >
          <BottomNavigation
            value={mobilePanel}
            onChange={(_, newValue) => {
              setMobilePanel(newValue === mobilePanel ? null : newValue);
            }}
            showLabels
          >
            <BottomNavigationAction
              label="Pagine"
              value="pages"
              icon={<PageIcon />}
            />
            <BottomNavigationAction
              label="Dati"
              value="data"
              icon={<DataIcon />}
            />
            <BottomNavigationAction
              label="Proprietà"
              value="properties"
              icon={<SettingsIcon />}
            />
          </BottomNavigation>
        </Paper>
      )}

      {/* Mobile Panel Drawer */}
      <SwipeableDrawer
        anchor="bottom"
        open={isMobile && mobilePanel !== null}
        onClose={() => setMobilePanel(null)}
        onOpen={() => {}}
        disableSwipeToOpen
        PaperProps={{
          sx: {
            height: "70vh",
            borderTopLeftRadius: 16,
            borderTopRightRadius: 16,
          },
        }}
      >
        <Box
          sx={{
            display: "flex",
            flexDirection: "column",
            height: "100%",
          }}
        >
          {/* Drawer Header */}
          <Box
            sx={{
              display: "flex",
              alignItems: "center",
              justifyContent: "space-between",
              p: 2,
              borderBottom: 1,
              borderColor: "divider",
            }}
          >
            <Typography variant="h6">{getMobilePanelTitle()}</Typography>
            <IconButton onClick={() => setMobilePanel(null)}>
              <CloseIcon />
            </IconButton>
          </Box>

          {/* Drawer Content */}
          <Box sx={{ flex: 1, overflow: "auto" }}>
            {renderMobileDrawerContent()}
          </Box>
        </Box>
      </SwipeableDrawer>

      {/* Save Dialog for new templates */}
      <Dialog
        open={saveDialog}
        onClose={() => setSaveDialog(false)}
        maxWidth="sm"
        fullWidth
        fullScreen={isMobile}
      >
        <DialogTitle>Salva Template</DialogTitle>
        <DialogContent>
          <Box display="flex" flexDirection="column" gap={2} mt={1}>
            <TextField
              label="Nome"
              value={templateInfo.nome}
              onChange={(e) =>
                setTemplateInfo((prev) => ({ ...prev, nome: e.target.value }))
              }
              fullWidth
              required
            />
            <TextField
              label="Descrizione"
              value={templateInfo.descrizione}
              onChange={(e) =>
                setTemplateInfo((prev) => ({
                  ...prev,
                  descrizione: e.target.value,
                }))
              }
              fullWidth
              multiline
              rows={2}
            />
            <FormControl fullWidth>
              <InputLabel>Categoria</InputLabel>
              <Select
                value={templateInfo.categoria}
                label="Categoria"
                onChange={(e) =>
                  setTemplateInfo((prev) => ({
                    ...prev,
                    categoria: e.target.value,
                  }))
                }
              >
                <MenuItem value="Generale">Generale</MenuItem>
                <MenuItem value="Evento">Evento</MenuItem>
                <MenuItem value="Cliente">Cliente</MenuItem>
                <MenuItem value="Articoli">Articoli</MenuItem>
              </Select>
            </FormControl>
          </Box>
        </DialogContent>
        <DialogActions sx={{ p: { xs: 2, sm: 1 } }}>
          <Button onClick={() => setSaveDialog(false)} fullWidth={isMobile}>
            Annulla
          </Button>
          <Button
            variant="contained"
            onClick={() =>
              saveMutation.mutate({ template, info: templateInfo })
            }
            disabled={!templateInfo.nome || saveMutation.isPending}
            fullWidth={isMobile}
          >
            {saveMutation.isPending ? "Salvataggio..." : "Salva"}
          </Button>
        </DialogActions>
      </Dialog>

      {/* Preview Dialog */}
      <PreviewDialog
        open={previewDialog}
        onClose={() => setPreviewDialog(false)}
        selectedDatasets={selectedDatasets}
        onGeneratePreview={handleGeneratePreview}
        isGenerating={isGeneratingPreview}
      />

      {/* Dataset Manager Dialog */}
      <DatasetManagerDialog
        open={datasetManagerDialog}
        onClose={() => setDatasetManagerDialog(false)}
        onDatasetCreated={() => {
          // Refresh both queries - available datasets now includes virtual datasets
          queryClient.invalidateQueries({ queryKey: ["available-datasets"] });
          queryClient.invalidateQueries({ queryKey: ["virtual-datasets"] });
        }}
      />

      {/* Image Upload Dialog */}
      <ImageUploadDialog
        open={imageUploadDialog}
        onClose={() => setImageUploadDialog(false)}
        onImageSelected={handleImageSelected}
      />

      {/* Context Menu */}
      <ContextMenu
        open={contextMenu.open}
        position={contextMenu.position}
        selectedElement={selectedElement || null}
        selectedElements={selectedElements}
        hasClipboard={clipboard !== null}
        onClose={closeContextMenu}
        // Clipboard actions
        onCopy={handleCopy}
        onCut={handleCut}
        onPaste={handlePaste}
        onDuplicate={handleDuplicate}
        onDelete={handleDeleteElement}
        // Lock actions
        onLock={handleToggleLock}
        onUnlock={handleUnlock}
        // Layer actions
        onBringToFront={handleBringToFront}
        onSendToBack={handleSendToBack}
        onBringForward={handleBringForward}
        onSendBackward={handleSendBackward}
        // Alignment actions
        onAlignLeft={handleAlignLeft}
        onAlignCenter={handleAlignCenter}
        onAlignRight={handleAlignRight}
        onAlignTop={handleAlignTop}
        onAlignMiddle={handleAlignMiddle}
        onAlignBottom={handleAlignBottom}
        onCenterOnPage={handleCenterOnPage}
        // Transform actions
        onRotateLeft={handleRotateLeft}
        onRotateRight={handleRotateRight}
        onFlipHorizontal={handleFlipHorizontal}
        onFlipVertical={handleFlipVertical}
        // Group actions
        onGroup={handleGroup}
        onUngroup={handleUngroup}
        // Selection actions
        onSelectAll={handleSelectAll}
        onDeselectAll={handleDeselectAll}
        // Visibility
        onToggleVisibility={handleToggleVisibility}
        // Type-specific actions
        onEditText={
          selectedElement?.type === "text" ? handleEditText : undefined
        }
        onReplaceImage={
          selectedElement?.type === "image" ? handleReplaceImage : undefined
        }
        onFitToContent={
          selectedElement?.type === "text" ? handleFitToContent : undefined
        }
      />

      {/* Snackbar */}
      <Snackbar
        open={snackbar.open}
        autoHideDuration={4000}
        onClose={() => setSnackbar((prev) => ({ ...prev, open: false }))}
      >
        <Alert
          severity={snackbar.severity}
          onClose={() => setSnackbar((prev) => ({ ...prev, open: false }))}
        >
          {snackbar.message}
        </Alert>
      </Snackbar>
    </Box>
  );
}
