"use client";

import Link from "next/link";
import { useEffect, useMemo, useRef, useState } from "react";

import { apiFetch } from "@/lib/api";
import { useDesktopEditorSupported } from "@/lib/editor-device";
import { Room, Table } from "@/lib/types";

type AreaFormState = {
  name: string;
  width: string;
  height: string;
  counter_name: string;
  counter_x: string;
  counter_y: string;
  counter_width: string;
  counter_height: string;
  counter_visible: boolean;
  entrance_name: string;
  entrance_x: string;
  entrance_y: string;
  entrance_width: string;
  entrance_height: string;
  entrance_visible: boolean;
  background_image_data_url: string | null;
};

type NewTableFormState = {
  name: string;
  width: string;
  height: string;
  shape: "square" | "round";
  rotation_degrees: string;
  min_seats: string;
  max_seats: string;
  join_group: string;
  is_active: boolean;
};

type TableEditFormState = {
  name: string;
  width: string;
  height: string;
  shape: "square" | "round";
  rotation_degrees: string;
  min_seats: string;
  max_seats: string;
  join_group: string;
  is_active: boolean;
};

type DragState = {
  kind: "table" | "counter" | "entrance";
  tableId?: number;
  startClientX: number;
  startClientY: number;
  originX: number;
  originY: number;
};

type ArmedTouchDragState = {
  tableId: number;
  expiresAt: number;
};

type TableShape = "square" | "round";

const EMPTY_NEW_AREA: AreaFormState = {
  name: "",
  width: "12",
  height: "8",
  counter_name: "Banco",
  counter_x: "0",
  counter_y: "0",
  counter_width: "1.8",
  counter_height: "2.8",
  counter_visible: true,
  entrance_name: "Entrata",
  entrance_x: "4.7",
  entrance_y: "6.2",
  entrance_width: "2.6",
  entrance_height: "1.8",
  entrance_visible: true,
  background_image_data_url: null
};

const EMPTY_NEW_TABLE: NewTableFormState = {
  name: "",
  width: "1.2",
  height: "1.2",
  shape: "square",
  rotation_degrees: "0",
  min_seats: "2",
  max_seats: "4",
  join_group: "",
  is_active: true
};

const EMPTY_TABLE_EDIT: TableEditFormState = {
  name: "",
  width: "",
  height: "",
  shape: "square",
  rotation_degrees: "0",
  min_seats: "",
  max_seats: "",
  join_group: "",
  is_active: true
};

function clamp(value: number, min: number, max: number): number {
  if (value < min) {
    return min;
  }
  if (value > max) {
    return max;
  }
  return value;
}

function roundToSingleDecimal(value: number): number {
  return Math.round(value * 10) / 10;
}

function parsePositiveNumber(value: string, label: string): number {
  const parsed = Number(value);
  if (!Number.isFinite(parsed) || parsed <= 0) {
    throw new Error(`${label} deve essere un numero maggiore di zero`);
  }
  return parsed;
}

function parseRotation(value: string): number {
  const parsed = Number(value);
  if (!Number.isFinite(parsed)) {
    throw new Error("Rotazione tavolo non valida");
  }
  const normalized = parsed % 360;
  return normalized < 0 ? normalized + 360 : normalized;
}

function normalizeTableDimensions(width: number, height: number, shape: TableShape): { width: number; height: number } {
  const side = Math.max(width, height);
  if (shape === "square" || shape === "round") {
    return {
      width: side,
      height: side
    };
  }
  return { width, height };
}

function normalizeTableShapeState(table: Table): Table {
  const dimensions = normalizeTableDimensions(table.width, table.height, table.shape);
  return {
    ...table,
    width: dimensions.width,
    height: dimensions.height
  };
}

function buildRenderedTableStyle(table: Table, previewRoom: Room) {
  const width = `${(table.width / previewRoom.width) * 100}%`;
  const height = `${(table.height / previewRoom.height) * 100}%`;

  return {
    left: `${(table.x / previewRoom.width) * 100}%`,
    top: `${(table.y / previewRoom.height) * 100}%`,
    width,
    ...(table.shape === "square" || table.shape === "round" ? { aspectRatio: "1 / 1" } : { height }),
    borderRadius: table.shape === "round" ? "999px" : "18px",
    ["--table-rotation" as string]: `${table.rotation_degrees}deg`
  };
}

function resolveVisibleCanvas(
  mobileCanvas: HTMLDivElement | null,
  desktopCanvas: HTMLDivElement | null
): HTMLDivElement | null {
  if (mobileCanvas && mobileCanvas.offsetParent !== null) {
    return mobileCanvas;
  }
  if (desktopCanvas && desktopCanvas.offsetParent !== null) {
    return desktopCanvas;
  }
  return mobileCanvas ?? desktopCanvas;
}

function isMobileTouchPointer(event: React.PointerEvent<HTMLElement>): boolean {
  if (event.pointerType !== "touch" || typeof window === "undefined") {
    return false;
  }
  return window.matchMedia("(max-width: 767px)").matches;
}

function resolvePreviewNumber(value: string, fallback: number): number {
  const parsed = Number(value);
  return Number.isFinite(parsed) ? parsed : fallback;
}

function resolvePreviewPositiveNumber(value: string, fallback: number): number {
  const parsed = Number(value);
  return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
}

function buildPreviewRoom(room: Room, form: AreaFormState): Room {
  return {
    ...room,
    width: resolvePreviewPositiveNumber(form.width, room.width),
    height: resolvePreviewPositiveNumber(form.height, room.height),
    counter_name: form.counter_name.trim() || room.counter_name || "Banco",
    counter_x: resolvePreviewNumber(form.counter_x, room.counter_x ?? 0),
    counter_y: resolvePreviewNumber(form.counter_y, room.counter_y ?? 0),
    counter_width: resolvePreviewPositiveNumber(form.counter_width, room.counter_width ?? 1.8),
    counter_height: resolvePreviewPositiveNumber(form.counter_height, room.counter_height ?? 2.8),
    counter_visible: form.counter_visible,
    entrance_name: form.entrance_name.trim() || room.entrance_name || "Entrata",
    entrance_x: resolvePreviewNumber(form.entrance_x, room.entrance_x ?? 0),
    entrance_y: resolvePreviewNumber(form.entrance_y, room.entrance_y ?? 0),
    entrance_width: resolvePreviewPositiveNumber(form.entrance_width, room.entrance_width ?? 2.6),
    entrance_height: resolvePreviewPositiveNumber(form.entrance_height, room.entrance_height ?? 1.8),
    entrance_visible: form.entrance_visible,
    background_image_data_url: form.background_image_data_url
  };
}

function buildRoomPayload(form: AreaFormState) {
  return {
    name: form.name.trim(),
    width: parsePositiveNumber(form.width, "Larghezza area"),
    height: parsePositiveNumber(form.height, "Altezza area"),
    counter_name: form.counter_name.trim() || "Banco",
    counter_x: Number(form.counter_x),
    counter_y: Number(form.counter_y),
    counter_width: parsePositiveNumber(form.counter_width, "Larghezza banco"),
    counter_height: parsePositiveNumber(form.counter_height, "Altezza banco"),
    counter_visible: form.counter_visible,
    entrance_name: form.entrance_name.trim() || "Entrata",
    entrance_x: Number(form.entrance_x),
    entrance_y: Number(form.entrance_y),
    entrance_width: parsePositiveNumber(form.entrance_width, "Larghezza entrata"),
    entrance_height: parsePositiveNumber(form.entrance_height, "Altezza entrata"),
    entrance_visible: form.entrance_visible,
    background_image_data_url: form.background_image_data_url
  };
}

async function fileToDataUrl(file: File): Promise<string> {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onload = () => {
      if (typeof reader.result === "string") {
        resolve(reader.result);
        return;
      }
      reject(new Error("Impossibile leggere l'immagine"));
    };
    reader.onerror = () => reject(new Error("Impossibile leggere l'immagine"));
    reader.readAsDataURL(file);
  });
}

export default function TablesPage() {
  const desktopEditorSupported = useDesktopEditorSupported();
  const [rooms, setRooms] = useState<Room[]>([]);
  const [selectedRoomId, setSelectedRoomId] = useState("");
  const [tables, setTables] = useState<Table[]>([]);
  const [selectedTableId, setSelectedTableId] = useState<number | null>(null);
  const [editingTable, setEditingTable] = useState<TableEditFormState>(EMPTY_TABLE_EDIT);
  const [areaForm, setAreaForm] = useState<AreaFormState>(EMPTY_NEW_AREA);
  const [newAreaForm, setNewAreaForm] = useState<AreaFormState>(EMPTY_NEW_AREA);
  const [newTableForm, setNewTableForm] = useState<NewTableFormState>(EMPTY_NEW_TABLE);
  const [showAreaEditor, setShowAreaEditor] = useState(true);
  const [editorZoom, setEditorZoom] = useState(1);
  const [showNewAreaBuilder, setShowNewAreaBuilder] = useState(false);
  const [showNewTableBuilder, setShowNewTableBuilder] = useState(false);
  const [armedTouchDrag, setArmedTouchDrag] = useState<ArmedTouchDragState | null>(null);
  const [dragging, setDragging] = useState<DragState | null>(null);
  const [message, setMessage] = useState<string | null>(null);
  const [error, setError] = useState<string | null>(null);
  const mobileCanvasRef = useRef<HTMLDivElement | null>(null);
  const desktopCanvasRef = useRef<HTMLDivElement | null>(null);
  const tablesRef = useRef<Table[]>([]);

  useEffect(() => {
    tablesRef.current = tables;
  }, [tables]);

  useEffect(() => {
    if (!armedTouchDrag || typeof window === "undefined") {
      return;
    }

    const timeout = Math.max(armedTouchDrag.expiresAt - Date.now(), 0);
    const timer = window.setTimeout(() => {
      setArmedTouchDrag((current) =>
        current?.tableId === armedTouchDrag.tableId ? null : current
      );
    }, timeout);

    return () => window.clearTimeout(timer);
  }, [armedTouchDrag]);

  const activeRoom = useMemo(
    () => rooms.find((room) => String(room.id) === selectedRoomId) ?? null,
    [rooms, selectedRoomId]
  );

  const selectedTable = useMemo(
    () => tables.find((table) => table.id === selectedTableId) ?? null,
    [tables, selectedTableId]
  );

  const previewRoom = useMemo(
    () => (activeRoom ? buildPreviewRoom(activeRoom, areaForm) : null),
    [activeRoom, areaForm]
  );

  const previewTables = useMemo(() => {
    if (!previewRoom) {
      return tables;
    }

    return tables.map((table) => {
      const baseWidth =
        table.id === selectedTableId ? resolvePreviewPositiveNumber(editingTable.width, table.width) : table.width;
      const baseHeight =
        table.id === selectedTableId ? resolvePreviewPositiveNumber(editingTable.height, table.height) : table.height;
      const dimensions = normalizeTableDimensions(
        baseWidth,
        baseHeight,
        table.id === selectedTableId ? editingTable.shape : table.shape
      );

      if (table.id !== selectedTableId) {
        return {
          ...table,
          width: dimensions.width,
          height: dimensions.height,
          x: clamp(table.x, 0, Math.max(0, previewRoom.width - dimensions.width)),
          y: clamp(table.y, 0, Math.max(0, previewRoom.height - dimensions.height))
        };
      }

      const minSeats = Math.max(1, Math.round(resolvePreviewPositiveNumber(editingTable.min_seats, table.min_seats)));
      const maxSeats = Math.max(
        minSeats,
        Math.round(resolvePreviewPositiveNumber(editingTable.max_seats, table.max_seats))
      );
      const rotation = Number.isFinite(Number(editingTable.rotation_degrees))
        ? parseRotation(editingTable.rotation_degrees)
        : table.rotation_degrees;

      return {
        ...table,
        name: editingTable.name.trim() || table.name,
        width: dimensions.width,
        height: dimensions.height,
        shape: editingTable.shape,
        rotation_degrees: rotation,
        min_seats: minSeats,
        max_seats: maxSeats,
        join_group: editingTable.join_group.trim() || null,
        is_active: editingTable.is_active,
        x: clamp(table.x, 0, Math.max(0, previewRoom.width - dimensions.width)),
        y: clamp(table.y, 0, Math.max(0, previewRoom.height - dimensions.height))
      };
    });
  }, [editingTable, previewRoom, selectedTableId, tables]);

  const previewSelectedTable = useMemo(
    () => previewTables.find((table) => table.id === selectedTableId) ?? null,
    [previewTables, selectedTableId]
  );

  useEffect(() => {
    if (!activeRoom) {
      return;
    }
    setAreaForm({
      name: activeRoom.name,
      width: String(activeRoom.width),
      height: String(activeRoom.height),
      counter_name: activeRoom.counter_name || "Banco",
      counter_x: String(activeRoom.counter_x ?? 0),
      counter_y: String(activeRoom.counter_y ?? 0),
      counter_width: String(activeRoom.counter_width ?? 1.8),
      counter_height: String(activeRoom.counter_height ?? 2.8),
      counter_visible: activeRoom.counter_visible,
      entrance_name: activeRoom.entrance_name || "Entrata",
      entrance_x: String(activeRoom.entrance_x ?? 0),
      entrance_y: String(activeRoom.entrance_y ?? 0),
      entrance_width: String(activeRoom.entrance_width ?? 2.6),
      entrance_height: String(activeRoom.entrance_height ?? 1.8),
      entrance_visible: activeRoom.entrance_visible,
      background_image_data_url: activeRoom.background_image_data_url
    });
  }, [activeRoom]);

  useEffect(() => {
    if (!selectedTable) {
      setEditingTable(EMPTY_TABLE_EDIT);
      return;
    }
    const dimensions = normalizeTableDimensions(selectedTable.width, selectedTable.height, selectedTable.shape);
    setEditingTable({
      name: selectedTable.name,
      width: String(dimensions.width),
      height: String(dimensions.height),
      shape: selectedTable.shape,
      rotation_degrees: String(selectedTable.rotation_degrees),
      min_seats: String(selectedTable.min_seats),
      max_seats: String(selectedTable.max_seats),
      join_group: selectedTable.join_group ?? "",
      is_active: selectedTable.is_active
    });
  }, [selectedTable]);

  async function loadRooms(preferredRoomId?: string) {
    const roomResults = await apiFetch<Room[]>("/rooms");
    setRooms(roomResults);

    const nextSelectedRoomId =
      preferredRoomId ||
      selectedRoomId ||
      (roomResults[0] ? String(roomResults[0].id) : "");
    setSelectedRoomId(nextSelectedRoomId);
    return nextSelectedRoomId;
  }

  async function loadTables(roomId: string) {
    if (!roomId) {
      setTables([]);
      setSelectedTableId(null);
      return;
    }
    const nextTables = (await apiFetch<Table[]>(`/tables?room_id=${roomId}`)).map(normalizeTableShapeState);
    setTables(nextTables);
    setSelectedTableId((current) => {
      if (current && nextTables.some((table) => table.id === current)) {
        return current;
      }
      return nextTables[0]?.id ?? null;
    });
  }

  useEffect(() => {
    async function bootstrap() {
      try {
        setError(null);
        const initialRoomId = await loadRooms();
        if (initialRoomId) {
          await loadTables(initialRoomId);
        }
      } catch (err) {
        setError(err instanceof Error ? err.message : "Impossibile caricare la configurazione della piantina");
      }
    }

    void bootstrap();
  }, []);

  useEffect(() => {
    if (!selectedRoomId) {
      return;
    }
    setArmedTouchDrag(null);
    void loadTables(selectedRoomId).catch((err: unknown) => {
      setError(err instanceof Error ? err.message : "Impossibile caricare i tavoli dell'area");
    });
  }, [selectedRoomId]);

  async function handleCreateArea(event: React.FormEvent<HTMLFormElement>) {
    event.preventDefault();
    try {
      setError(null);
      const payload = buildRoomPayload(newAreaForm);
      const created = await apiFetch<Room>("/rooms", {
        method: "POST",
        body: JSON.stringify(payload)
      });
      setNewAreaForm(EMPTY_NEW_AREA);
      setShowNewAreaBuilder(false);
      await loadRooms(String(created.id));
      await loadTables(String(created.id));
      setMessage(`Area "${created.name}" creata.`);
    } catch (err) {
      setError(err instanceof Error ? err.message : "Impossibile creare l'area");
    }
  }

  async function handleUpdateArea(event: React.FormEvent<HTMLFormElement>) {
    event.preventDefault();
    if (!activeRoom) {
      return;
    }
    try {
      setError(null);
      const payload = buildRoomPayload(areaForm);
      const updated = await apiFetch<Room>(`/rooms/${activeRoom.id}`, {
        method: "PUT",
        body: JSON.stringify(payload)
      });
      setRooms((current) =>
        current.map((room) => (room.id === updated.id ? updated : room))
      );
      setMessage(`Area "${updated.name}" aggiornata.`);
    } catch (err) {
      setError(err instanceof Error ? err.message : "Impossibile aggiornare l'area");
    }
  }

  async function handleResetRoom() {
    if (!activeRoom) {
      return;
    }

    try {
      setError(null);
      const updated = await apiFetch<Room>(`/rooms/${activeRoom.id}/reset-layout`, {
        method: "POST"
      });
      setRooms((current) => current.map((room) => (room.id === updated.id ? updated : room)));
      await loadTables(String(updated.id));
      setMessage(`Piantina di "${updated.name}" azzerata. Ora puoi ricrearla da zero.`);
    } catch (err) {
      setError(err instanceof Error ? err.message : "Impossibile azzerare la piantina");
    }
  }

  async function handleBackgroundUpload(
    event: React.ChangeEvent<HTMLInputElement>,
    target: "active" | "new"
  ) {
    const file = event.target.files?.[0];
    if (!file) {
      return;
    }

    try {
      setError(null);
      const dataUrl = await fileToDataUrl(file);
      if (target === "active") {
        setAreaForm((current) => ({ ...current, background_image_data_url: dataUrl }));
      } else {
        setNewAreaForm((current) => ({ ...current, background_image_data_url: dataUrl }));
      }
      setMessage(`Sfondo caricato. Salva l'area per confermarlo.`);
    } catch (err) {
      setError(err instanceof Error ? err.message : "Impossibile caricare lo sfondo");
    } finally {
      event.target.value = "";
    }
  }

  async function handleCreateTable(event: React.FormEvent<HTMLFormElement>) {
    event.preventDefault();
    if (!activeRoom) {
      setError("Seleziona prima un'area");
      return;
    }

    try {
      setError(null);
      const dimensions = normalizeTableDimensions(
        parsePositiveNumber(newTableForm.width, "Larghezza tavolo"),
        parsePositiveNumber(newTableForm.height, "Altezza tavolo"),
        newTableForm.shape
      );
      const minSeats = Math.round(parsePositiveNumber(newTableForm.min_seats, "Coperti minimi"));
      const maxSeats = Math.round(parsePositiveNumber(newTableForm.max_seats, "Coperti massimi"));

      if (maxSeats < minSeats) {
        throw new Error("Coperti massimi deve essere maggiore o uguale ai coperti minimi");
      }

      const centerX = clamp(
        (activeRoom.width - dimensions.width) / 2,
        0,
        Math.max(0, activeRoom.width - dimensions.width)
      );
      const centerY = clamp(
        (activeRoom.height - dimensions.height) / 2,
        0,
        Math.max(0, activeRoom.height - dimensions.height)
      );

      const created = normalizeTableShapeState(await apiFetch<Table>("/tables", {
        method: "POST",
        body: JSON.stringify({
          room_id: activeRoom.id,
          name: newTableForm.name.trim(),
          x: centerX,
          y: centerY,
          width: dimensions.width,
          height: dimensions.height,
          shape: newTableForm.shape,
          rotation_degrees: parseRotation(newTableForm.rotation_degrees),
          min_seats: minSeats,
          max_seats: maxSeats,
          join_group: newTableForm.join_group.trim() || null,
          is_active: newTableForm.is_active
        })
      }));

      setTables((current) => [...current, created]);
      setSelectedTableId(created.id);
      setNewTableForm((current) => ({ ...EMPTY_NEW_TABLE, join_group: current.join_group }));
      setShowNewTableBuilder(false);
      setMessage(`Tavolo "${created.name}" creato e posizionato nella mappa.`);
    } catch (err) {
      setError(err instanceof Error ? err.message : "Impossibile creare il tavolo");
    }
  }

  async function handleSaveTableDetails(event: React.FormEvent<HTMLFormElement>) {
    event.preventDefault();
    if (!selectedTable || !activeRoom) {
      return;
    }

    try {
      setError(null);
      const dimensions = normalizeTableDimensions(
        parsePositiveNumber(editingTable.width, "Larghezza tavolo"),
        parsePositiveNumber(editingTable.height, "Altezza tavolo"),
        editingTable.shape
      );
      const minSeats = Math.round(parsePositiveNumber(editingTable.min_seats, "Coperti minimi"));
      const maxSeats = Math.round(parsePositiveNumber(editingTable.max_seats, "Coperti massimi"));

      if (maxSeats < minSeats) {
        throw new Error("Coperti massimi deve essere maggiore o uguale ai coperti minimi");
      }

      const clampedX = clamp(selectedTable.x, 0, Math.max(0, activeRoom.width - dimensions.width));
      const clampedY = clamp(selectedTable.y, 0, Math.max(0, activeRoom.height - dimensions.height));

      const updated = normalizeTableShapeState(await apiFetch<Table>(`/tables/${selectedTable.id}`, {
        method: "PUT",
        body: JSON.stringify({
          room_id: activeRoom.id,
          name: editingTable.name.trim(),
          x: clampedX,
          y: clampedY,
          width: dimensions.width,
          height: dimensions.height,
          shape: editingTable.shape,
          rotation_degrees: parseRotation(editingTable.rotation_degrees),
          min_seats: minSeats,
          max_seats: maxSeats,
          join_group: editingTable.join_group.trim() || null,
          is_active: editingTable.is_active
        })
      }));

      setTables((current) =>
        current.map((table) => (table.id === updated.id ? updated : table))
      );
      setSelectedTableId(updated.id);
      setMessage(`Dettagli del tavolo "${updated.name}" salvati.`);
    } catch (err) {
      setError(err instanceof Error ? err.message : "Impossibile salvare il tavolo");
    }
  }

  async function handleDeleteSelectedTable() {
    if (!selectedTable) {
      return;
    }

    const confirmed = window.confirm(`Vuoi eliminare il tavolo "${selectedTable.name}"?`);
    if (!confirmed) {
      return;
    }

    try {
      setError(null);
      const response = await apiFetch<{
        deleted_id: number;
        removed_combinations: number;
        cleared_reservations: number;
        detail: string;
      }>(`/tables/${selectedTable.id}`, {
        method: "DELETE"
      });
      setTables((current) => current.filter((table) => table.id !== selectedTable.id));
      setSelectedTableId((current) => (current === selectedTable.id ? null : current));
      setMessage(response.detail);
    } catch (err) {
      setError(err instanceof Error ? err.message : "Impossibile eliminare il tavolo");
    }
  }

  async function persistDraggedTable(table: Table, origin: DragState) {
    if (!activeRoom) {
      return;
    }

    const moved = Math.abs(table.x - origin.originX) > 0.005 || Math.abs(table.y - origin.originY) > 0.005;
    if (!moved) {
      return;
    }

    try {
      const updated = normalizeTableShapeState(await apiFetch<Table>(`/tables/${table.id}`, {
        method: "PUT",
        body: JSON.stringify({
          room_id: activeRoom.id,
          name: table.name,
          x: table.x,
          y: table.y,
          width: table.width,
          height: table.height,
          shape: table.shape,
          rotation_degrees: table.rotation_degrees,
          min_seats: table.min_seats,
          max_seats: table.max_seats,
          join_group: table.join_group,
          is_active: table.is_active
        })
      }));
      setTables((current) =>
        current.map((currentTable) => (currentTable.id === updated.id ? updated : currentTable))
      );
      setMessage(`Posizione tavolo "${updated.name}" aggiornata.`);
    } catch (err) {
      setError(err instanceof Error ? err.message : "Impossibile salvare lo spostamento del tavolo");
      await loadTables(selectedRoomId);
    }
  }

  async function persistDraggedCounter(nextX: number, nextY: number, origin: DragState) {
    if (!activeRoom) {
      return;
    }

    const moved = Math.abs(nextX - origin.originX) > 0.005 || Math.abs(nextY - origin.originY) > 0.005;
    if (!moved) {
      return;
    }

    try {
      const payload = buildRoomPayload({
        ...areaForm,
        counter_x: String(nextX),
        counter_y: String(nextY)
      });
      const updated = await apiFetch<Room>(`/rooms/${activeRoom.id}`, {
        method: "PUT",
        body: JSON.stringify(payload)
      });
      setRooms((current) => current.map((room) => (room.id === updated.id ? updated : room)));
      setMessage(`Posizione del banco aggiornata.`);
    } catch (err) {
      setError(err instanceof Error ? err.message : "Impossibile salvare lo spostamento del banco");
      const refreshedRooms = await apiFetch<Room[]>("/rooms");
      setRooms(refreshedRooms);
    }
  }

  async function persistDraggedEntrance(nextX: number, nextY: number, origin: DragState) {
    if (!activeRoom) {
      return;
    }

    const moved = Math.abs(nextX - origin.originX) > 0.005 || Math.abs(nextY - origin.originY) > 0.005;
    if (!moved) {
      return;
    }

    try {
      const payload = buildRoomPayload({
        ...areaForm,
        entrance_x: String(nextX),
        entrance_y: String(nextY)
      });
      const updated = await apiFetch<Room>(`/rooms/${activeRoom.id}`, {
        method: "PUT",
        body: JSON.stringify(payload)
      });
      setRooms((current) => current.map((room) => (room.id === updated.id ? updated : room)));
      setMessage(`Posizione dell'entrata aggiornata.`);
    } catch (err) {
      setError(err instanceof Error ? err.message : "Impossibile salvare lo spostamento dell'entrata");
      const refreshedRooms = await apiFetch<Room[]>("/rooms");
      setRooms(refreshedRooms);
    }
  }

  function handleTablePointerDown(event: React.PointerEvent<HTMLButtonElement>, table: Table) {
    if (!activeRoom) {
      return;
    }
    event.preventDefault();
    setSelectedTableId(table.id);

    if (isMobileTouchPointer(event)) {
      const now = Date.now();
      const isArmedSelection =
        selectedTableId === table.id &&
        armedTouchDrag?.tableId === table.id &&
        armedTouchDrag.expiresAt > now;

      if (!isArmedSelection) {
        setArmedTouchDrag({
          tableId: table.id,
          expiresAt: now + 4000
        });
        return;
      }
    }

    setArmedTouchDrag(null);
    setDragging({
      kind: "table",
      tableId: table.id,
      startClientX: event.clientX,
      startClientY: event.clientY,
      originX: table.x,
      originY: table.y
    });
  }

  function handleCounterPointerDown(event: React.PointerEvent<HTMLButtonElement>) {
    const room = previewRoom ?? activeRoom;
    if (!room || room.counter_x === null || room.counter_y === null) {
      return;
    }
    event.preventDefault();
    setDragging({
      kind: "counter",
      startClientX: event.clientX,
      startClientY: event.clientY,
      originX: room.counter_x,
      originY: room.counter_y
    });
  }

  function handleEntrancePointerDown(event: React.PointerEvent<HTMLButtonElement>) {
    const room = previewRoom ?? activeRoom;
    if (!room || room.entrance_x === null || room.entrance_y === null) {
      return;
    }
    event.preventDefault();
    setDragging({
      kind: "entrance",
      startClientX: event.clientX,
      startClientY: event.clientY,
      originX: room.entrance_x,
      originY: room.entrance_y
    });
  }

  useEffect(() => {
    if (!dragging || !activeRoom) {
      return;
    }
    const drag = dragging;
    const room = previewRoom ?? activeRoom;

    function handlePointerMove(event: PointerEvent) {
      const canvas = resolveVisibleCanvas(mobileCanvasRef.current, desktopCanvasRef.current);
      if (!canvas) {
        return;
      }
      const rect = canvas.getBoundingClientRect();
      if (rect.width <= 0 || rect.height <= 0) {
        return;
      }

      const meterPerPixelX = room.width / rect.width;
      const meterPerPixelY = room.height / rect.height;
      const deltaX = (event.clientX - drag.startClientX) * meterPerPixelX;
      const deltaY = (event.clientY - drag.startClientY) * meterPerPixelY;

      if (drag.kind === "counter") {
        const counterWidth = room.counter_width ?? 1.8;
        const counterHeight = room.counter_height ?? 2.8;
        const nextX = clamp(drag.originX + deltaX, 0, Math.max(0, room.width - counterWidth));
        const nextY = clamp(drag.originY + deltaY, 0, Math.max(0, room.height - counterHeight));
        setRooms((current) =>
          current.map((currentRoom) =>
                currentRoom.id === room.id
              ? {
                  ...buildPreviewRoom(currentRoom, areaForm),
                  counter_x: roundToSingleDecimal(nextX),
                  counter_y: roundToSingleDecimal(nextY)
                }
              : currentRoom
          )
        );
        return;
      }

      if (drag.kind === "entrance") {
        const entranceWidth = room.entrance_width ?? 2.6;
        const entranceHeight = room.entrance_height ?? 1.8;
        const nextX = clamp(drag.originX + deltaX, 0, Math.max(0, room.width - entranceWidth));
        const nextY = clamp(drag.originY + deltaY, 0, Math.max(0, room.height - entranceHeight));
        setRooms((current) =>
          current.map((currentRoom) =>
                currentRoom.id === room.id
              ? {
                  ...buildPreviewRoom(currentRoom, areaForm),
                  entrance_x: roundToSingleDecimal(nextX),
                  entrance_y: roundToSingleDecimal(nextY)
                }
              : currentRoom
          )
        );
        return;
      }

      setTables((current) =>
        current.map((table) => {
          if (table.id !== drag.tableId) {
            return table;
          }
          const nextX = clamp(
            drag.originX + deltaX,
            0,
            Math.max(0, room.width - table.width)
          );
          const nextY = clamp(
            drag.originY + deltaY,
            0,
            Math.max(0, room.height - table.height)
          );
          return {
            ...table,
            x: roundToSingleDecimal(nextX),
            y: roundToSingleDecimal(nextY)
          };
        })
      );
    }

    function handlePointerUp() {
      const snapshot = drag;
      setDragging(null);
      setArmedTouchDrag(null);
      if (snapshot.kind === "counter") {
        const currentRoom = rooms.find((current) => current.id === room.id);
        if (currentRoom && currentRoom.counter_x !== null && currentRoom.counter_y !== null) {
          void persistDraggedCounter(currentRoom.counter_x, currentRoom.counter_y, snapshot);
        }
        return;
      }
      if (snapshot.kind === "entrance") {
        const currentRoom = rooms.find((current) => current.id === room.id);
        if (currentRoom && currentRoom.entrance_x !== null && currentRoom.entrance_y !== null) {
          void persistDraggedEntrance(currentRoom.entrance_x, currentRoom.entrance_y, snapshot);
        }
        return;
      }
      const movedTable = tablesRef.current.find((table) => table.id === snapshot.tableId);
      if (!movedTable) {
        return;
      }
      void persistDraggedTable(movedTable, snapshot);
    }

    window.addEventListener("pointermove", handlePointerMove);
    window.addEventListener("pointerup", handlePointerUp);

    return () => {
      window.removeEventListener("pointermove", handlePointerMove);
      window.removeEventListener("pointerup", handlePointerUp);
    };
  }, [activeRoom, areaForm, dragging, previewRoom, rooms, selectedRoomId]);

  const orderedTables = useMemo(
    () =>
      [...previewTables].sort((a, b) => {
        const aNumeric = Number(a.name);
        const bNumeric = Number(b.name);
        if (!Number.isNaN(aNumeric) && !Number.isNaN(bNumeric)) {
          return aNumeric - bNumeric;
        }
        return a.name.localeCompare(b.name);
      }),
    [previewTables]
  );

  if (desktopEditorSupported === null) {
    return (
      <main className="space-y-6">
        <section className="panel max-w-3xl">
          <p className="section-kicker">Editor piantina</p>
          <h2 className="mt-3 section-title">Verifica dispositivo in corso</h2>
          <p className="mt-3 section-intro">
            Sto controllando se questo browser puo usare l&apos;editor completo della piantina.
          </p>
        </section>
      </main>
    );
  }

  if (desktopEditorSupported !== true) {
    return (
      <main className="space-y-6">
        <section className="panel max-w-3xl">
          <p className="section-kicker">Editor piantina</p>
          <h2 className="mt-3 section-title">Disponibile solo da PC</h2>
          <p className="mt-3 section-intro">
            L&apos;editor completo della piantina resta attivo solo su desktop, per evitare modifiche accidentali da
            cellulare o tablet touch. Da qui puoi continuare a consultare la piantina operativa.
          </p>
          <div className="mt-5 flex flex-wrap gap-3">
            <Link className="button-primary" href="/floor-plan">
              Apri piantina
            </Link>
            <Link className="button-secondary" href="/reservations">
              Torna alle prenotazioni
            </Link>
          </div>
        </section>
      </main>
    );
  }

  const canvasAspectRatio = previewRoom ? `${previewRoom.width} / ${previewRoom.height}` : "16 / 10";
  const canvasBackgroundImage = previewRoom?.background_image_data_url || null;
  const editorZoomPercent = Math.round(editorZoom * 100);

  function adjustEditorZoom(delta: number) {
    setEditorZoom((current) => clamp(Math.round((current + delta) * 100) / 100, 0.75, 1.8));
  }

  return (
    <main className={`editor-page-layout${showAreaEditor ? "" : " is-sidebar-collapsed"}`}>
      <aside className={`panel space-y-8 editor-sidebar-panel${showAreaEditor ? "" : " is-collapsed"}`}>
        <div className="editor-sidebar-header">
          <div>
            <p className="section-kicker">Strumenti editor</p>
            <h2 className="mt-3 section-title">Aggiungi tavoli, aree e misure</h2>
            <p className="mt-3 section-intro">
              Tutte le operazioni di costruzione della sala stanno qui. La piantina resta al centro e gli strumenti
              spariscono quando non ti servono.
            </p>
          </div>
        </div>

        <form className="grid gap-4 md:grid-cols-2" onSubmit={(event) => void handleUpdateArea(event)}>
          <label className="block md:col-span-2">
            <span className="mb-2 block text-sm text-stone-600">Area attiva</span>
            <select
              className="field"
              value={selectedRoomId}
              onChange={(event) => setSelectedRoomId(event.target.value)}
            >
              <option value="">Seleziona area</option>
              {rooms.map((room) => (
                <option key={room.id} value={room.id}>
                  {room.name}
                </option>
              ))}
            </select>
          </label>
          <label className="block md:col-span-2">
            <span className="mb-2 block text-sm text-stone-600">Nome area</span>
            <input
              className="field"
              value={areaForm.name}
              onChange={(event) => setAreaForm((current) => ({ ...current, name: event.target.value }))}
              disabled={!activeRoom}
              required
            />
          </label>
          <label className="block">
            <span className="mb-2 block text-sm text-stone-600">Larghezza area (m)</span>
            <input
              className="field"
              type="number"
              step="0.1"
              min="0.1"
              value={areaForm.width}
              onChange={(event) => setAreaForm((current) => ({ ...current, width: event.target.value }))}
              disabled={!activeRoom}
              required
            />
          </label>
          <label className="block">
            <span className="mb-2 block text-sm text-stone-600">Altezza area (m)</span>
            <input
              className="field"
              type="number"
              step="0.1"
              min="0.1"
              value={areaForm.height}
              onChange={(event) => setAreaForm((current) => ({ ...current, height: event.target.value }))}
              disabled={!activeRoom}
              required
            />
          </label>
          <label className="block md:col-span-2">
            <span className="mb-2 block text-sm text-stone-600">Nome banco</span>
            <input
              className="field"
              value={areaForm.counter_name}
              onChange={(event) => setAreaForm((current) => ({ ...current, counter_name: event.target.value }))}
              disabled={!activeRoom}
            />
          </label>
          <label className="block">
            <span className="mb-2 block text-sm text-stone-600">Larghezza banco (m)</span>
            <input
              className="field"
              type="number"
              step="0.1"
              min="0.1"
              value={areaForm.counter_width}
              onChange={(event) => setAreaForm((current) => ({ ...current, counter_width: event.target.value }))}
              disabled={!activeRoom}
              required
            />
          </label>
          <label className="block">
            <span className="mb-2 block text-sm text-stone-600">Altezza banco (m)</span>
            <input
              className="field"
              type="number"
              step="0.1"
              min="0.1"
              value={areaForm.counter_height}
              onChange={(event) => setAreaForm((current) => ({ ...current, counter_height: event.target.value }))}
              disabled={!activeRoom}
              required
            />
          </label>
          <label className="block">
            <span className="mb-2 block text-sm text-stone-600">Posizione banco X (m)</span>
            <input
              className="field"
              type="number"
              step="0.1"
              min="0"
              value={areaForm.counter_x}
              onChange={(event) => setAreaForm((current) => ({ ...current, counter_x: event.target.value }))}
              disabled={!activeRoom}
            />
          </label>
          <label className="block">
            <span className="mb-2 block text-sm text-stone-600">Posizione banco Y (m)</span>
            <input
              className="field"
              type="number"
              step="0.1"
              min="0"
              value={areaForm.counter_y}
              onChange={(event) => setAreaForm((current) => ({ ...current, counter_y: event.target.value }))}
              disabled={!activeRoom}
            />
          </label>
          <label className="flex items-center gap-3 rounded-[16px] border border-stone-200 bg-white px-4 py-3 md:col-span-2">
            <input
              type="checkbox"
              checked={areaForm.counter_visible}
              onChange={(event) => setAreaForm((current) => ({ ...current, counter_visible: event.target.checked }))}
              disabled={!activeRoom}
            />
            <span className="text-sm text-stone-700">Mostra banco in piantina</span>
          </label>
          <label className="block md:col-span-2">
            <span className="mb-2 block text-sm text-stone-600">Nome entrata</span>
            <input
              className="field"
              value={areaForm.entrance_name}
              onChange={(event) => setAreaForm((current) => ({ ...current, entrance_name: event.target.value }))}
              disabled={!activeRoom}
            />
          </label>
          <label className="block">
            <span className="mb-2 block text-sm text-stone-600">Larghezza entrata (m)</span>
            <input
              className="field"
              type="number"
              step="0.1"
              min="0.1"
              value={areaForm.entrance_width}
              onChange={(event) => setAreaForm((current) => ({ ...current, entrance_width: event.target.value }))}
              disabled={!activeRoom}
              required
            />
          </label>
          <label className="block">
            <span className="mb-2 block text-sm text-stone-600">Altezza entrata (m)</span>
            <input
              className="field"
              type="number"
              step="0.1"
              min="0.1"
              value={areaForm.entrance_height}
              onChange={(event) => setAreaForm((current) => ({ ...current, entrance_height: event.target.value }))}
              disabled={!activeRoom}
              required
            />
          </label>
          <label className="block">
            <span className="mb-2 block text-sm text-stone-600">Posizione entrata X (m)</span>
            <input
              className="field"
              type="number"
              step="0.1"
              min="0"
              value={areaForm.entrance_x}
              onChange={(event) => setAreaForm((current) => ({ ...current, entrance_x: event.target.value }))}
              disabled={!activeRoom}
            />
          </label>
          <label className="block">
            <span className="mb-2 block text-sm text-stone-600">Posizione entrata Y (m)</span>
            <input
              className="field"
              type="number"
              step="0.1"
              min="0"
              value={areaForm.entrance_y}
              onChange={(event) => setAreaForm((current) => ({ ...current, entrance_y: event.target.value }))}
              disabled={!activeRoom}
            />
          </label>
          <label className="flex items-center gap-3 rounded-[16px] border border-stone-200 bg-white px-4 py-3 md:col-span-2">
            <input
              type="checkbox"
              checked={areaForm.entrance_visible}
              onChange={(event) => setAreaForm((current) => ({ ...current, entrance_visible: event.target.checked }))}
              disabled={!activeRoom}
            />
            <span className="text-sm text-stone-700">Mostra entrata in piantina</span>
          </label>
          <div className="md:col-span-2 rounded-[20px] border border-stone-200 bg-white/80 p-4">
            <div className="flex flex-col gap-3 md:flex-row md:items-center md:justify-between">
              <div>
                <p className="text-sm font-semibold text-stone-800">Foto di sfondo</p>
                <p className="mt-1 text-sm text-stone-500">
                  Carica la foto della sala come base per costruire la piantina.
                </p>
              </div>
              <div className="flex flex-wrap gap-3">
                <label className="button-secondary cursor-pointer">
                  Carica foto
                  <input
                    className="hidden"
                    type="file"
                    accept="image/*"
                    onChange={(event) => void handleBackgroundUpload(event, "active")}
                  />
                </label>
                <button
                  className="button-secondary"
                  type="button"
                  onClick={() => setAreaForm((current) => ({ ...current, background_image_data_url: null }))}
                  disabled={!areaForm.background_image_data_url}
                >
                  Rimuovi sfondo
                </button>
              </div>
            </div>
            {areaForm.background_image_data_url ? (
              <div className="mt-4 overflow-hidden rounded-[18px] border border-stone-200">
                <img alt="Anteprima sfondo sala" className="h-40 w-full object-cover" src={areaForm.background_image_data_url} />
              </div>
            ) : null}
          </div>
          <div className="space-y-4 md:col-span-2 md:hidden">
            {activeRoom ? (
              <div className="flex flex-wrap gap-3">
                <label className="flex items-center gap-3 rounded-[16px] border border-stone-200 bg-white/80 px-4 py-3">
                  <input
                    type="checkbox"
                    checked={areaForm.counter_visible}
                    onChange={(event) =>
                      setAreaForm((current) => ({ ...current, counter_visible: event.target.checked }))
                    }
                  />
                  <span className="text-sm text-stone-700">Visualizza banco</span>
                </label>
                <label className="flex items-center gap-3 rounded-[16px] border border-stone-200 bg-white/80 px-4 py-3">
                  <input
                    type="checkbox"
                    checked={areaForm.entrance_visible}
                    onChange={(event) =>
                      setAreaForm((current) => ({ ...current, entrance_visible: event.target.checked }))
                    }
                  />
                  <span className="text-sm text-stone-700">Visualizza entrata</span>
                </label>
              </div>
            ) : null}

            <div className="layout-editor-shell">
              <div
                ref={mobileCanvasRef}
                className={`layout-editor-canvas ${dragging ? "is-dragging" : ""}`}
                style={{ aspectRatio: canvasAspectRatio }}
              >
                {previewRoom ? <div className="layout-editor-grid" /> : null}
                {canvasBackgroundImage ? (
                  <div
                    className="layout-editor-background"
                    style={{ backgroundImage: `url(${canvasBackgroundImage})` }}
                  />
                ) : null}
                {previewRoom && activeRoom ? (
                  <>
                    {previewRoom.entrance_visible &&
                    previewRoom.entrance_x !== null &&
                    previewRoom.entrance_y !== null &&
                    previewRoom.entrance_width !== null &&
                    previewRoom.entrance_height !== null ? (
                      <button
                        type="button"
                        className="layout-editor-entrance"
                        style={{
                          left: `${(previewRoom.entrance_x / previewRoom.width) * 100}%`,
                          top: `${(previewRoom.entrance_y / previewRoom.height) * 100}%`,
                          width: `${(previewRoom.entrance_width / previewRoom.width) * 100}%`,
                          height: `${(previewRoom.entrance_height / previewRoom.height) * 100}%`
                        }}
                        onPointerDown={(event) => handleEntrancePointerDown(event)}
                      >
                        <span>{previewRoom.entrance_name || "Entrata"}</span>
                        <small>trascina</small>
                      </button>
                    ) : null}
                    {previewRoom.counter_visible &&
                    previewRoom.counter_x !== null &&
                    previewRoom.counter_y !== null &&
                    previewRoom.counter_width !== null &&
                    previewRoom.counter_height !== null ? (
                      <button
                        type="button"
                        className="layout-editor-counter"
                        style={{
                          left: `${(previewRoom.counter_x / previewRoom.width) * 100}%`,
                          top: `${(previewRoom.counter_y / previewRoom.height) * 100}%`,
                          width: `${(previewRoom.counter_width / previewRoom.width) * 100}%`,
                          height: `${(previewRoom.counter_height / previewRoom.height) * 100}%`
                        }}
                        onPointerDown={(event) => handleCounterPointerDown(event)}
                      >
                        <span>{previewRoom.counter_name || "Banco"}</span>
                        <small>trascina</small>
                      </button>
                    ) : null}
                    {orderedTables.map((table) => (
                      <button
                        type="button"
                        key={table.id}
                        className={`layout-editor-table layout-editor-table--${table.shape} ${
                          selectedTableId === table.id ? "is-selected" : ""
                        } ${table.is_active ? "" : "is-inactive"}`}
                        style={buildRenderedTableStyle(table, previewRoom)}
                        onPointerDown={(event) => handleTablePointerDown(event, table)}
                        onClick={() => setSelectedTableId(table.id)}
                      >
                        <span>{table.name}</span>
                        <small>
                          {table.min_seats}-{table.max_seats} pax
                        </small>
                      </button>
                    ))}
                  </>
                ) : (
                  <p className="layout-editor-empty">Nessuna area disponibile.</p>
                )}
              </div>
            </div>
          </div>
          <div className="md:col-span-2">
            <div className="flex flex-wrap gap-3">
              <button className="button-secondary flex-1" type="submit" disabled={!activeRoom}>
                Salva area attiva
              </button>
              <button className="button-primary flex-1" type="button" disabled={!activeRoom} onClick={() => void handleResetRoom()}>
                Nuova piantina
              </button>
            </div>
          </div>
        </form>

        <div className="layout-builder-actions md:hidden">
          <button
            type="button"
            className="layout-builder-toggle"
            aria-expanded={showNewAreaBuilder}
            onClick={() => setShowNewAreaBuilder((current) => !current)}
          >
            <span>Nuova area</span>
            <small>{showNewAreaBuilder ? "Chiudi" : "Apri"}</small>
          </button>

          {showNewAreaBuilder ? (
            <form className="layout-builder-panel grid gap-4 md:grid-cols-2" onSubmit={(event) => void handleCreateArea(event)}>
              <label className="block md:col-span-2">
                <span className="mb-2 block text-sm text-stone-600">Nome</span>
                <input
                  className="field"
                  value={newAreaForm.name}
                  onChange={(event) => setNewAreaForm((current) => ({ ...current, name: event.target.value }))}
                  required
                />
              </label>
              <label className="block">
                <span className="mb-2 block text-sm text-stone-600">Larghezza (m)</span>
                <input
                  className="field"
                  type="number"
                  step="0.1"
                  min="0.1"
                  value={newAreaForm.width}
                  onChange={(event) => setNewAreaForm((current) => ({ ...current, width: event.target.value }))}
                  required
                />
              </label>
              <label className="block">
                <span className="mb-2 block text-sm text-stone-600">Altezza (m)</span>
                <input
                  className="field"
                  type="number"
                  step="0.1"
                  min="0.1"
                  value={newAreaForm.height}
                  onChange={(event) => setNewAreaForm((current) => ({ ...current, height: event.target.value }))}
                  required
                />
              </label>
              <label className="block md:col-span-2">
                <span className="mb-2 block text-sm text-stone-600">Nome entrata iniziale</span>
                <input
                  className="field"
                  value={newAreaForm.entrance_name}
                  onChange={(event) => setNewAreaForm((current) => ({ ...current, entrance_name: event.target.value }))}
                />
              </label>
              <label className="block">
                <span className="mb-2 block text-sm text-stone-600">Larghezza entrata (m)</span>
                <input
                  className="field"
                  type="number"
                  step="0.1"
                  min="0.1"
                  value={newAreaForm.entrance_width}
                  onChange={(event) => setNewAreaForm((current) => ({ ...current, entrance_width: event.target.value }))}
                  required
                />
              </label>
              <label className="block">
                <span className="mb-2 block text-sm text-stone-600">Altezza entrata (m)</span>
                <input
                  className="field"
                  type="number"
                  step="0.1"
                  min="0.1"
                  value={newAreaForm.entrance_height}
                  onChange={(event) => setNewAreaForm((current) => ({ ...current, entrance_height: event.target.value }))}
                  required
                />
              </label>
              <label className="block">
                <span className="mb-2 block text-sm text-stone-600">Posizione entrata X (m)</span>
                <input
                  className="field"
                  type="number"
                  step="0.1"
                  min="0"
                  value={newAreaForm.entrance_x}
                  onChange={(event) => setNewAreaForm((current) => ({ ...current, entrance_x: event.target.value }))}
                />
              </label>
              <label className="block">
                <span className="mb-2 block text-sm text-stone-600">Posizione entrata Y (m)</span>
                <input
                  className="field"
                  type="number"
                  step="0.1"
                  min="0"
                  value={newAreaForm.entrance_y}
                  onChange={(event) => setNewAreaForm((current) => ({ ...current, entrance_y: event.target.value }))}
                />
              </label>
              <label className="flex items-center gap-3 rounded-[16px] border border-stone-200 bg-white px-4 py-3 md:col-span-2">
                <input
                  type="checkbox"
                  checked={newAreaForm.entrance_visible}
                  onChange={(event) => setNewAreaForm((current) => ({ ...current, entrance_visible: event.target.checked }))}
                />
                <span className="text-sm text-stone-700">Mostra entrata iniziale</span>
              </label>
              <div className="md:col-span-2 rounded-[18px] border border-stone-200 bg-white p-4">
                <div className="flex flex-wrap gap-3">
                  <label className="button-secondary cursor-pointer">
                    Carica sfondo iniziale
                    <input
                      className="hidden"
                      type="file"
                      accept="image/*"
                      onChange={(event) => void handleBackgroundUpload(event, "new")}
                    />
                  </label>
                  <button
                    className="button-secondary"
                    type="button"
                    onClick={() => setNewAreaForm((current) => ({ ...current, background_image_data_url: null }))}
                    disabled={!newAreaForm.background_image_data_url}
                  >
                    Rimuovi sfondo
                  </button>
                </div>
                {newAreaForm.background_image_data_url ? (
                  <div className="mt-4 overflow-hidden rounded-[16px] border border-stone-200">
                    <img alt="Anteprima nuovo sfondo sala" className="h-32 w-full object-cover" src={newAreaForm.background_image_data_url} />
                  </div>
                ) : null}
              </div>
              <div className="md:col-span-2">
                <button className="button-primary w-full" type="submit">Crea area</button>
              </div>
            </form>
          ) : null}

          <button
            type="button"
            className="layout-builder-toggle"
            aria-expanded={showNewTableBuilder}
            disabled={!activeRoom}
            onClick={() => setShowNewTableBuilder((current) => !current)}
          >
            <span>Nuovo tavolo</span>
            <small>{!activeRoom ? "Seleziona prima un'area" : showNewTableBuilder ? "Chiudi" : "Apri"}</small>
          </button>

          {showNewTableBuilder ? (
            <form className="layout-builder-panel grid gap-4 md:grid-cols-2" onSubmit={(event) => void handleCreateTable(event)}>
              <label className="block md:col-span-2">
                <span className="mb-2 block text-sm text-stone-600">Nome tavolo</span>
                <input
                  className="field"
                  value={newTableForm.name}
                  onChange={(event) => setNewTableForm((current) => ({ ...current, name: event.target.value }))}
                  required
                />
              </label>
              <label className="block">
                <span className="mb-2 block text-sm text-stone-600">Larghezza (m)</span>
                <input
                  className="field"
                  type="number"
                  step="0.1"
                  min="0.1"
                  value={newTableForm.width}
                  onChange={(event) => setNewTableForm((current) => ({ ...current, width: event.target.value }))}
                  required
                />
              </label>
              <label className="block">
                <span className="mb-2 block text-sm text-stone-600">Altezza (m)</span>
                <input
                  className="field"
                  type="number"
                  step="0.1"
                  min="0.1"
                  value={newTableForm.height}
                  onChange={(event) => setNewTableForm((current) => ({ ...current, height: event.target.value }))}
                  required
                />
              </label>
              <label className="block">
                <span className="mb-2 block text-sm text-stone-600">Forma tavolo</span>
                <select
                  className="field"
                  value={newTableForm.shape}
                  onChange={(event) =>
                    setNewTableForm((current) => ({
                      ...current,
                      shape: event.target.value as "square" | "round"
                    }))
                  }
                >
                  <option value="square">Quadrato</option>
                  <option value="round">Rotondo</option>
                </select>
              </label>
              <label className="block">
                <span className="mb-2 block text-sm text-stone-600">Rotazione (gradi)</span>
                <input
                  className="field"
                  type="number"
                  min="0"
                  max="359"
                  step="15"
                  value={newTableForm.rotation_degrees}
                  onChange={(event) => setNewTableForm((current) => ({ ...current, rotation_degrees: event.target.value }))}
                  required
                />
              </label>
              <label className="block">
                <span className="mb-2 block text-sm text-stone-600">Coperti minimi</span>
                <input
                  className="field"
                  type="number"
                  min="1"
                  value={newTableForm.min_seats}
                  onChange={(event) => setNewTableForm((current) => ({ ...current, min_seats: event.target.value }))}
                  required
                />
              </label>
              <label className="block">
                <span className="mb-2 block text-sm text-stone-600">Coperti massimi</span>
                <input
                  className="field"
                  type="number"
                  min="1"
                  value={newTableForm.max_seats}
                  onChange={(event) => setNewTableForm((current) => ({ ...current, max_seats: event.target.value }))}
                  required
                />
              </label>
              <label className="block md:col-span-2">
                <span className="mb-2 block text-sm text-stone-600">Gruppo combinazione (opzionale)</span>
                <input
                  className="field"
                  value={newTableForm.join_group}
                  onChange={(event) => setNewTableForm((current) => ({ ...current, join_group: event.target.value }))}
                />
              </label>
              <label className="flex items-center gap-3 rounded-[16px] border border-stone-200 bg-white px-4 py-3 md:col-span-2">
                <input
                  type="checkbox"
                  checked={newTableForm.is_active}
                  onChange={(event) => setNewTableForm((current) => ({ ...current, is_active: event.target.checked }))}
                />
                <span className="text-sm text-stone-700">Tavolo attivo</span>
              </label>
              <div className="md:col-span-2">
                <button className="button-primary w-full" type="submit" disabled={!activeRoom}>
                  Aggiungi tavolo al centro area
                </button>
              </div>
            </form>
          ) : null}
        </div>

        <form className="hidden gap-4 rounded-[24px] border border-stone-200 bg-white/80 p-4 md:grid md:grid-cols-2" onSubmit={(event) => void handleCreateArea(event)}>
          <p className="md:col-span-2 text-xs uppercase tracking-[0.16em] text-stone-500">Nuova area</p>
          <label className="block md:col-span-2">
            <span className="mb-2 block text-sm text-stone-600">Nome</span>
            <input
              className="field"
              value={newAreaForm.name}
              onChange={(event) => setNewAreaForm((current) => ({ ...current, name: event.target.value }))}
              required
            />
          </label>
          <label className="block">
            <span className="mb-2 block text-sm text-stone-600">Larghezza (m)</span>
            <input
              className="field"
              type="number"
              step="0.1"
              min="0.1"
              value={newAreaForm.width}
              onChange={(event) => setNewAreaForm((current) => ({ ...current, width: event.target.value }))}
              required
            />
          </label>
          <label className="block">
            <span className="mb-2 block text-sm text-stone-600">Altezza (m)</span>
            <input
              className="field"
              type="number"
              step="0.1"
              min="0.1"
              value={newAreaForm.height}
              onChange={(event) => setNewAreaForm((current) => ({ ...current, height: event.target.value }))}
              required
            />
          </label>
          <label className="block md:col-span-2">
            <span className="mb-2 block text-sm text-stone-600">Nome entrata iniziale</span>
            <input
              className="field"
              value={newAreaForm.entrance_name}
              onChange={(event) => setNewAreaForm((current) => ({ ...current, entrance_name: event.target.value }))}
            />
          </label>
          <label className="block">
            <span className="mb-2 block text-sm text-stone-600">Larghezza entrata (m)</span>
            <input
              className="field"
              type="number"
              step="0.1"
              min="0.1"
              value={newAreaForm.entrance_width}
              onChange={(event) => setNewAreaForm((current) => ({ ...current, entrance_width: event.target.value }))}
              required
            />
          </label>
          <label className="block">
            <span className="mb-2 block text-sm text-stone-600">Altezza entrata (m)</span>
            <input
              className="field"
              type="number"
              step="0.1"
              min="0.1"
              value={newAreaForm.entrance_height}
              onChange={(event) => setNewAreaForm((current) => ({ ...current, entrance_height: event.target.value }))}
              required
            />
          </label>
          <label className="block">
            <span className="mb-2 block text-sm text-stone-600">Posizione entrata X (m)</span>
            <input
              className="field"
              type="number"
              step="0.1"
              min="0"
              value={newAreaForm.entrance_x}
              onChange={(event) => setNewAreaForm((current) => ({ ...current, entrance_x: event.target.value }))}
            />
          </label>
          <label className="block">
            <span className="mb-2 block text-sm text-stone-600">Posizione entrata Y (m)</span>
            <input
              className="field"
              type="number"
              step="0.1"
              min="0"
              value={newAreaForm.entrance_y}
              onChange={(event) => setNewAreaForm((current) => ({ ...current, entrance_y: event.target.value }))}
            />
          </label>
          <label className="flex items-center gap-3 rounded-[16px] border border-stone-200 bg-white px-4 py-3 md:col-span-2">
            <input
              type="checkbox"
              checked={newAreaForm.entrance_visible}
              onChange={(event) => setNewAreaForm((current) => ({ ...current, entrance_visible: event.target.checked }))}
            />
            <span className="text-sm text-stone-700">Mostra entrata iniziale</span>
          </label>
          <div className="md:col-span-2 rounded-[18px] border border-stone-200 bg-white p-4">
            <div className="flex flex-wrap gap-3">
              <label className="button-secondary cursor-pointer">
                Carica sfondo iniziale
                <input
                  className="hidden"
                  type="file"
                  accept="image/*"
                  onChange={(event) => void handleBackgroundUpload(event, "new")}
                />
              </label>
              <button
                className="button-secondary"
                type="button"
                onClick={() => setNewAreaForm((current) => ({ ...current, background_image_data_url: null }))}
                disabled={!newAreaForm.background_image_data_url}
              >
                Rimuovi sfondo
              </button>
            </div>
            {newAreaForm.background_image_data_url ? (
              <div className="mt-4 overflow-hidden rounded-[16px] border border-stone-200">
                <img alt="Anteprima nuovo sfondo sala" className="h-32 w-full object-cover" src={newAreaForm.background_image_data_url} />
              </div>
            ) : null}
          </div>
          <div className="md:col-span-2">
            <button className="button-primary w-full" type="submit">Crea area</button>
          </div>
        </form>

        <form className="hidden gap-4 rounded-[24px] border border-stone-200 bg-white/80 p-4 md:grid md:grid-cols-2" onSubmit={(event) => void handleCreateTable(event)}>
          <p className="md:col-span-2 text-xs uppercase tracking-[0.16em] text-stone-500">Nuovo tavolo</p>
          <label className="block md:col-span-2">
            <span className="mb-2 block text-sm text-stone-600">Nome tavolo</span>
            <input
              className="field"
              value={newTableForm.name}
              onChange={(event) => setNewTableForm((current) => ({ ...current, name: event.target.value }))}
              required
            />
          </label>
          <label className="block">
            <span className="mb-2 block text-sm text-stone-600">Larghezza (m)</span>
            <input
              className="field"
              type="number"
              step="0.1"
              min="0.1"
              value={newTableForm.width}
              onChange={(event) => setNewTableForm((current) => ({ ...current, width: event.target.value }))}
              required
            />
          </label>
          <label className="block">
            <span className="mb-2 block text-sm text-stone-600">Altezza (m)</span>
            <input
              className="field"
              type="number"
              step="0.1"
              min="0.1"
              value={newTableForm.height}
              onChange={(event) => setNewTableForm((current) => ({ ...current, height: event.target.value }))}
              required
            />
          </label>
          <label className="block">
            <span className="mb-2 block text-sm text-stone-600">Forma tavolo</span>
            <select
              className="field"
              value={newTableForm.shape}
              onChange={(event) =>
                setNewTableForm((current) => ({
                  ...current,
                  shape: event.target.value as "square" | "round"
                }))
              }
            >
              <option value="square">Quadrato</option>
              <option value="round">Rotondo</option>
            </select>
          </label>
          <label className="block">
            <span className="mb-2 block text-sm text-stone-600">Rotazione (gradi)</span>
            <input
              className="field"
              type="number"
              min="0"
              max="359"
              step="15"
              value={newTableForm.rotation_degrees}
              onChange={(event) => setNewTableForm((current) => ({ ...current, rotation_degrees: event.target.value }))}
              required
            />
          </label>
          <label className="block">
            <span className="mb-2 block text-sm text-stone-600">Coperti minimi</span>
            <input
              className="field"
              type="number"
              min="1"
              value={newTableForm.min_seats}
              onChange={(event) => setNewTableForm((current) => ({ ...current, min_seats: event.target.value }))}
              required
            />
          </label>
          <label className="block">
            <span className="mb-2 block text-sm text-stone-600">Coperti massimi</span>
            <input
              className="field"
              type="number"
              min="1"
              value={newTableForm.max_seats}
              onChange={(event) => setNewTableForm((current) => ({ ...current, max_seats: event.target.value }))}
              required
            />
          </label>
          <label className="block md:col-span-2">
            <span className="mb-2 block text-sm text-stone-600">Gruppo combinazione (opzionale)</span>
            <input
              className="field"
              value={newTableForm.join_group}
              onChange={(event) => setNewTableForm((current) => ({ ...current, join_group: event.target.value }))}
            />
          </label>
          <label className="flex items-center gap-3 rounded-[16px] border border-stone-200 bg-white px-4 py-3 md:col-span-2">
            <input
              type="checkbox"
              checked={newTableForm.is_active}
              onChange={(event) => setNewTableForm((current) => ({ ...current, is_active: event.target.checked }))}
            />
            <span className="text-sm text-stone-700">Tavolo attivo</span>
          </label>
          <div className="md:col-span-2">
            <button className="button-primary w-full" type="submit" disabled={!activeRoom}>
              Aggiungi tavolo al centro area
            </button>
          </div>
        </form>

        {message ? <p className="notice">{message}</p> : null}
        {error ? <p className="notice is-error">{error}</p> : null}
      </aside>

      <section className="panel space-y-6 editor-stage-panel">
        <div className="space-y-6">
          <div className="editor-stage-toolbar">
            <button
              className={`button-ghost editor-sidebar-toggle${showAreaEditor ? " is-active" : ""}`}
              type="button"
              onClick={() => setShowAreaEditor((current) => !current)}
              aria-label={showAreaEditor ? "Chiudi menu strumenti" : "Apri menu strumenti"}
              aria-expanded={showAreaEditor}
            >
              <span className="editor-hamburger" aria-hidden="true">
                <span />
                <span />
                <span />
              </span>
            </button>
            <div className="editor-stage-copy">
              <p className="section-kicker">Editor piantina</p>
              <h2 className="mt-3 section-title">Piantina centrale del locale</h2>
              <p className="mt-3 section-intro">
                Trascina entrata, banco e tavoli direttamente sulla sala. Le modifiche restano protagoniste della
                pagina e il menu strumenti si apre solo quando serve.
              </p>
            </div>
            <div className="editor-stage-actions">
              <div className="editor-zoom-controls" aria-label="Controlli zoom piantina">
                <span className="editor-zoom-label">Zoom</span>
                <div className="editor-zoom-group">
                  <button
                    className="button-ghost editor-zoom-button"
                    type="button"
                    onClick={() => adjustEditorZoom(-0.15)}
                    disabled={editorZoom <= 0.75}
                    aria-label="Riduci zoom"
                  >
                    -
                  </button>
                  <button
                    className="button-ghost editor-zoom-value"
                    type="button"
                    onClick={() => setEditorZoom(1)}
                    aria-label="Reimposta zoom"
                  >
                    {editorZoomPercent}%
                  </button>
                  <button
                    className="button-secondary editor-zoom-button"
                    type="button"
                    onClick={() => adjustEditorZoom(0.15)}
                    disabled={editorZoom >= 1.8}
                    aria-label="Aumenta zoom"
                  >
                    +
                  </button>
                </div>
              </div>
            </div>
          </div>

          {message ? <p className="notice">{message}</p> : null}
          {error ? <p className="notice is-error">{error}</p> : null}

          {activeRoom ? (
            <div className="flex flex-wrap gap-3">
              <label className="flex items-center gap-3 rounded-[16px] border border-stone-200 bg-white/80 px-4 py-3">
                <input
                  type="checkbox"
                  checked={areaForm.counter_visible}
                  onChange={(event) =>
                    setAreaForm((current) => ({ ...current, counter_visible: event.target.checked }))
                  }
                />
                <span className="text-sm text-stone-700">Visualizza banco</span>
              </label>
              <label className="flex items-center gap-3 rounded-[16px] border border-stone-200 bg-white/80 px-4 py-3">
                <input
                  type="checkbox"
                  checked={areaForm.entrance_visible}
                  onChange={(event) =>
                    setAreaForm((current) => ({ ...current, entrance_visible: event.target.checked }))
                  }
                />
                <span className="text-sm text-stone-700">Visualizza entrata</span>
              </label>
            </div>
          ) : null}

          <div className="layout-editor-shell editor-stage-canvas-shell">
            <div className="layout-editor-zoom-frame" style={{ width: `${editorZoomPercent}%` }}>
              <div
                ref={desktopCanvasRef}
                className={`layout-editor-canvas ${dragging ? "is-dragging" : ""}`}
                style={{ aspectRatio: canvasAspectRatio }}
              >
                {previewRoom ? <div className="layout-editor-grid" /> : null}
                {canvasBackgroundImage ? (
                  <div
                    className="layout-editor-background"
                    style={{ backgroundImage: `url(${canvasBackgroundImage})` }}
                  />
                ) : null}
                {previewRoom && activeRoom ? (
                  <>
                    {previewRoom.entrance_visible &&
                    previewRoom.entrance_x !== null &&
                    previewRoom.entrance_y !== null &&
                    previewRoom.entrance_width !== null &&
                    previewRoom.entrance_height !== null ? (
                      <button
                        type="button"
                        className="layout-editor-entrance"
                        style={{
                          left: `${(previewRoom.entrance_x / previewRoom.width) * 100}%`,
                          top: `${(previewRoom.entrance_y / previewRoom.height) * 100}%`,
                          width: `${(previewRoom.entrance_width / previewRoom.width) * 100}%`,
                          height: `${(previewRoom.entrance_height / previewRoom.height) * 100}%`
                        }}
                        onPointerDown={(event) => handleEntrancePointerDown(event)}
                      >
                        <span>{previewRoom.entrance_name || "Entrata"}</span>
                        <small>trascina</small>
                      </button>
                    ) : null}
                    {previewRoom.counter_visible &&
                    previewRoom.counter_x !== null &&
                    previewRoom.counter_y !== null &&
                    previewRoom.counter_width !== null &&
                    previewRoom.counter_height !== null ? (
                      <button
                        type="button"
                        className="layout-editor-counter"
                        style={{
                          left: `${(previewRoom.counter_x / previewRoom.width) * 100}%`,
                          top: `${(previewRoom.counter_y / previewRoom.height) * 100}%`,
                          width: `${(previewRoom.counter_width / previewRoom.width) * 100}%`,
                          height: `${(previewRoom.counter_height / previewRoom.height) * 100}%`
                        }}
                        onPointerDown={(event) => handleCounterPointerDown(event)}
                      >
                        <span>{previewRoom.counter_name || "Banco"}</span>
                        <small>trascina</small>
                      </button>
                    ) : null}
                    {orderedTables.map((table) => (
                      <button
                        type="button"
                        key={table.id}
                        className={`layout-editor-table layout-editor-table--${table.shape} ${
                          selectedTableId === table.id ? "is-selected" : ""
                        } ${table.is_active ? "" : "is-inactive"}`}
                        style={buildRenderedTableStyle(table, previewRoom)}
                        onPointerDown={(event) => handleTablePointerDown(event, table)}
                        onClick={() => setSelectedTableId(table.id)}
                      >
                        <span>{table.name}</span>
                        <small>{table.min_seats}-{table.max_seats} pax</small>
                      </button>
                    ))}
                  </>
                ) : (
                  <p className="layout-editor-empty">Nessuna area disponibile.</p>
                )}
              </div>
            </div>
          </div>
        </div>

        <div>
          <p className="section-kicker">Tavolo selezionato</p>
          <h2 className="mt-3 section-title">Dettagli del tavolo</h2>
          <p className="mt-3 section-intro">
            Seleziona un tavolo nella piantina per aggiornarne misure, coperti, forma e rotazione.
          </p>
        </div>

        {selectedTable && activeRoom ? (
          <form className="grid gap-4 rounded-[24px] border border-stone-200 bg-white/80 p-4 md:grid-cols-2" onSubmit={(event) => void handleSaveTableDetails(event)}>
            <p className="md:col-span-2 text-xs uppercase tracking-[0.16em] text-stone-500">Tavolo selezionato</p>
            <label className="block md:col-span-2">
              <span className="mb-2 block text-sm text-stone-600">Nome</span>
              <input
                className="field"
                value={editingTable.name}
                onChange={(event) => setEditingTable((current) => ({ ...current, name: event.target.value }))}
                required
              />
            </label>
            <label className="block">
              <span className="mb-2 block text-sm text-stone-600">Larghezza (m)</span>
              <input
                className="field"
                type="number"
                step="0.1"
                min="0.1"
                value={editingTable.width}
                onChange={(event) => setEditingTable((current) => ({ ...current, width: event.target.value }))}
                required
              />
            </label>
            <label className="block">
              <span className="mb-2 block text-sm text-stone-600">Altezza (m)</span>
              <input
                className="field"
                type="number"
                step="0.1"
                min="0.1"
                value={editingTable.height}
                onChange={(event) => setEditingTable((current) => ({ ...current, height: event.target.value }))}
                required
              />
            </label>
            <label className="block">
              <span className="mb-2 block text-sm text-stone-600">Forma tavolo</span>
              <select
                className="field"
                value={editingTable.shape}
                onChange={(event) =>
                  setEditingTable((current) => ({
                    ...current,
                    shape: event.target.value as "square" | "round"
                  }))
                }
              >
                <option value="square">Quadrato</option>
                <option value="round">Rotondo</option>
              </select>
            </label>
            <label className="block">
              <span className="mb-2 block text-sm text-stone-600">Rotazione (gradi)</span>
              <input
                className="field"
                type="number"
                min="0"
                max="359"
                step="15"
                value={editingTable.rotation_degrees}
                onChange={(event) => setEditingTable((current) => ({ ...current, rotation_degrees: event.target.value }))}
                required
              />
            </label>
            <label className="block">
              <span className="mb-2 block text-sm text-stone-600">Coperti minimi</span>
              <input
                className="field"
                type="number"
                min="1"
                value={editingTable.min_seats}
                onChange={(event) => setEditingTable((current) => ({ ...current, min_seats: event.target.value }))}
                required
              />
            </label>
            <label className="block">
              <span className="mb-2 block text-sm text-stone-600">Coperti massimi</span>
              <input
                className="field"
                type="number"
                min="1"
                value={editingTable.max_seats}
                onChange={(event) => setEditingTable((current) => ({ ...current, max_seats: event.target.value }))}
                required
              />
            </label>
            <label className="block md:col-span-2">
              <span className="mb-2 block text-sm text-stone-600">Gruppo combinazione</span>
              <input
                className="field"
                value={editingTable.join_group}
                onChange={(event) => setEditingTable((current) => ({ ...current, join_group: event.target.value }))}
              />
            </label>
            <label className="flex items-center gap-3 rounded-[16px] border border-stone-200 bg-white px-4 py-3 md:col-span-2">
              <input
                type="checkbox"
                checked={editingTable.is_active}
                onChange={(event) => setEditingTable((current) => ({ ...current, is_active: event.target.checked }))}
              />
              <span className="text-sm text-stone-700">Tavolo attivo</span>
            </label>
            <div className="rounded-[16px] border border-stone-200 bg-stone-100 px-4 py-3 md:col-span-2 text-sm text-stone-700">
              Posizione attuale: {(previewSelectedTable ?? selectedTable).x.toFixed(1)} m,{" "}
              {(previewSelectedTable ?? selectedTable).y.toFixed(1)} m
            </div>
            <div className="md:col-span-2 flex flex-wrap gap-3">
              <button className="button-secondary flex-1" type="submit">
                Salva dettagli tavolo
              </button>
              <button
                className="button-ghost flex-1 border-red-500/30 text-red-200 hover:border-red-400/50"
                type="button"
                onClick={() => void handleDeleteSelectedTable()}
              >
                Elimina tavolo
              </button>
            </div>
          </form>
        ) : (
          <p className="text-sm text-stone-500">Seleziona un tavolo nella mappa per modificarne i dettagli.</p>
        )}
      </section>
    </main>
  );
}
