import { mdiContentSave, mdiExitToApp, mdiPlus } from '@mdi/js';
import axios from 'axios';
import Head from 'next/head';
import { useRouter } from 'next/router';
import React, {
  ReactElement,
  useCallback,
  useEffect,
  useMemo,
  useRef,
  useState,
} from 'react';
import BaseButton from '../components/BaseButton';
import CanvasBackground from '../components/Constructor/CanvasBackground';
import ConstructorControlsPanel from '../components/Constructor/ConstructorControlsPanel';
import ConstructorMenu from '../components/Constructor/ConstructorMenu';
import TransitionPreviewOverlay from '../components/Constructor/TransitionPreviewOverlay';
import CanvasElementComponent from '../components/Constructor/CanvasElement';
import GalleryCarouselOverlay from '../components/UiElements/GalleryCarouselOverlay';
import ElementEditorPanel from '../components/Constructor/ElementEditorPanel';
import { getPageTitle } from '../config';
import LayoutAuthenticated from '../layouts/Authenticated';
import { usePreloadOrchestrator } from '../hooks/usePreloadOrchestrator';
import { extractPageLinksAndElements } from '../lib/extractPageLinks';
import { usePageSwitch } from '../hooks/usePageSwitch';
import { useTransitionPlayback } from '../hooks/useTransitionPlayback';
import { useBackgroundTransition } from '../hooks/useBackgroundTransition';
import { logger } from '../lib/logger';
import { resolveAssetPlaybackUrl } from '../lib/assetUrl';
import { parseJsonObject } from '../lib/parseJson';
import {
  resolveNavigationTarget,
  hasPlayableTransition,
  getNavigationDirection,
} from '../lib/navigationHelpers';
import {
  mergeElementWithDefaults,
  createLocalId,
  normalizeAppearDelaySec,
  normalizeAppearDurationSec,
  ELEMENT_TYPE_LABELS,
  getNavigationButtonKind,
  isNavigationElementType,
  isTooltipElementType,
  isDescriptionElementType,
  isMediaElementType,
  isVideoPlayerElementType,
} from '../lib/elementDefaults';
import type { PreloadPageLink, PreloadElement } from '../types/preload';
import type {
  CanvasElementType,
  CanvasElement,
  ConstructorSchema,
  ConstructorAsset as ProjectAsset,
  NormalizedElementDefault,
} from '../types/constructor';
import {
  normalizeElementDefault,
  buildElementDefaultsMap,
} from '../types/constructor';

// Constructor-specific hooks
import {
  useCanvasElapsedTime,
  isElementVisibleAtTime,
} from '../hooks/useCanvasElapsedTime';
import {
  useMediaDurationProbe,
  buildDurationProbeTargets,
} from '../hooks/useMediaDurationProbe';
import { useIconPreload } from '../hooks/useIconPreload';
import { useOutsideClick } from '../hooks/useOutsideClick';
import { useDraggable } from '../hooks/useDraggable';
import { useCanvasElementDrag } from '../hooks/useCanvasElementDrag';
import { useTransitionPreview } from '../hooks/useTransitionPreview';
import { useConstructorPageActions } from '../hooks/useConstructorPageActions';
import { useConstructorElements } from '../hooks/useConstructorElements';

// Constructor helpers (extracted utilities)
import {
  clamp,
  getAssetLabel,
  getAssetSourceValue,
  isBackgroundImageAsset,
} from '../lib/constructorHelpers';

type TourPage = {
  id: string;
  name?: string;
  slug?: string;
  sort_order?: number;
  environment?: 'dev' | 'stage' | 'production';
  source_key?: string;
  requires_auth?: boolean;
  ui_schema_json?: string;
  background_image_url?: string;
  background_video_url?: string;
  background_audio_url?: string;
  background_loop?: boolean;
};

type NavigationElementType = Extract<
  CanvasElementType,
  'navigation_next' | 'navigation_prev'
>;

type EditorMenuItem =
  | 'none'
  | 'background_image'
  | 'background_video'
  | 'background_audio'
  | 'create_transition';

type ConstructorPageProps = {
  mode?: 'constructor' | 'element_edit';
};

type ConstructorInteractionMode = 'edit' | 'interact';

// Use ELEMENT_TYPE_LABELS from elementDefaults for label lookup
const labelByType = ELEMENT_TYPE_LABELS;

const ConstructorPage = ({ mode = 'constructor' }: ConstructorPageProps) => {
  const router = useRouter();
  const canvasRef = useRef<HTMLDivElement>(null);
  const elementEditorRef = useRef<HTMLDivElement>(null);
  const [isAuthReady, setIsAuthReady] = useState(false);
  const isElementEditMode = mode === 'element_edit';

  const projectId = useMemo(() => {
    const value = router.query.projectId;
    if (Array.isArray(value)) return value[0] || '';
    return String(value || '');
  }, [router.query.projectId]);
  const pageElementsListHref = useMemo(() => {
    if (!projectId)
      return '/project-element-defaults/project-element-defaults-list';
    return `/project-element-defaults/project-element-defaults-list?projectId=${encodeURIComponent(projectId)}`;
  }, [projectId]);

  const pageIdFromRoute = useMemo(() => {
    const value = router.query.pageId;
    if (Array.isArray(value)) return value[0] || '';
    return String(value || '');
  }, [router.query.pageId]);
  const elementIdFromRoute = useMemo(() => {
    const value = router.query.elementId;
    if (Array.isArray(value)) return value[0] || '';
    return String(value || '');
  }, [router.query.elementId]);

  const [pages, setPages] = useState<TourPage[]>([]);
  const [pageLinks, setPageLinks] = useState<PreloadPageLink[]>([]);
  const [allPagesPreloadElements, setAllPagesPreloadElements] = useState<
    PreloadElement[]
  >([]);
  const [assets, setAssets] = useState<ProjectAsset[]>([]);
  const [uiElementDefaultsByType, setUiElementDefaultsByType] = useState<
    Partial<Record<CanvasElementType, Partial<CanvasElement>>>
  >({});
  const [activePageId, setActivePageId] = useState('');
  const [projectName, setProjectName] = useState('');

  const [backgroundImageUrl, setBackgroundImageUrl] = useState('');
  const [backgroundVideoUrl, setBackgroundVideoUrl] = useState('');
  const [backgroundAudioUrl, setBackgroundAudioUrl] = useState('');
  const [selectedMenuItem, setSelectedMenuItem] =
    useState<EditorMenuItem>('none');
  // Transition preview state managed by useTransitionPreview hook (below)

  const [isLoading, setIsLoading] = useState(true);
  // isSaving, isSavingToStage, isCreatingPage are managed by useConstructorPageActions hook
  const [newTransitionName, setNewTransitionName] = useState('');
  const [newTransitionVideoUrl, setNewTransitionVideoUrl] = useState('');
  const [newTransitionSupportsReverse, setNewTransitionSupportsReverse] =
    useState(true);
  const [errorMessage, setErrorMessage] = useState('');
  const [successMessage, setSuccessMessage] = useState('');
  const [constructorInteractionMode, setConstructorInteractionMode] =
    useState<ConstructorInteractionMode>('edit');
  const [isMenuOpen, setIsMenuOpen] = useState(false);
  const [isEditorCollapsed, setIsEditorCollapsed] = useState(false);
  const [elementEditorTab, setElementEditorTab] = useState<
    'general' | 'css' | 'effects'
  >('general');
  const [activeGalleryCarousel, setActiveGalleryCarousel] = useState<{
    element: CanvasElement;
    initialIndex: number;
  } | null>(null);

  const isConstructorEditMode = constructorInteractionMode === 'edit';
  const allowedNavigationTypes = useMemo<NavigationElementType[]>(() => {
    return ['navigation_next', 'navigation_prev'];
  }, []);

  // Element CRUD operations via useConstructorElements hook
  const {
    elements,
    setElements,
    selectedElementId,
    selectedElement,
    selectElement,
    clearSelection,
    addElement,
    updateSelectedElement,
    removeSelectedElement,
    galleryCards,
    galleryInfoSpans,
    carouselSlides,
    updateElementPosition,
    normalizeNavigationType,
  } = useConstructorElements({
    initialElements: [],
    elementDefaultsByType: uiElementDefaultsByType,
    allowedNavigationTypes,
    initialSelectedElementId: elementIdFromRoute,
    onElementSelected: useCallback(() => {
      setSelectedMenuItem('none');
    }, []),
    onSelectionCleared: useCallback(() => {
      setSelectedMenuItem('none');
    }, []),
    onElementAdded: useCallback(() => {
      setSuccessMessage('Element added. Drag it to set position.');
      setErrorMessage('');
    }, []),
    onElementRemoved: useCallback(() => {
      setSuccessMessage('Element removed.');
    }, []),
  });

  // Draggable panels using useDraggable hook
  const {
    position: constructorControlsPosition,
    onDragStart: onConstructorControlsDragStart,
  } = useDraggable({
    initialPosition: { x: 20, y: 20 },
    elementWidth: 460,
    elementHeight: 64,
  });

  const { position: menuPosition, onDragStart: onMenuDragStart } = useDraggable(
    {
      initialPosition: { x: 9999, y: 10 }, // Top right corner (x will be clamped)
      elementWidth: 240,
      elementHeight: 60,
    },
  );

  const { position: editorPosition, onDragStart: onElementEditorDragStart } =
    useDraggable({
      initialPosition: { x: 0, y: 72 },
      elementWidth: isEditorCollapsed ? 260 : 380,
      elementHeight: 60,
    });

  const transitionVideoRef = useRef<HTMLVideoElement | null>(null);
  const lastInitializedPageIdRef = useRef<string | null>(null);
  const didSetInitialCanvasFocus = useRef(false);
  const selectedElementIdRef = useRef<string>('');
  selectedElementIdRef.current = selectedElementId;

  const activePage = useMemo(
    () => pages.find((item) => item.id === activePageId) || null,
    [activePageId, pages],
  );

  // Transition preview state management
  const {
    preview: transitionPreview,
    pendingPageId: pendingNavigationPageId,
    openPreview: openTransitionPreviewForElement,
    openPreviewWithTarget,
    closePreview: closeTransitionPreview,
  } = useTransitionPreview({
    isNavigationElementType,
    onError: setErrorMessage,
  });

  // Canvas elapsed time for element visibility timing
  const { elapsedSec: canvasElapsedSec } = useCanvasElapsedTime({
    pageId: activePageId,
    enabled: !isLoading,
  });

  // Element dragging with percentage positioning
  const { onElementDragStart, cancelDrag: cancelElementDrag } =
    useCanvasElementDrag({
      canvasRef,
      onPositionChange: updateElementPosition,
      enabled: constructorInteractionMode === 'edit',
    });

  // Preload orchestrator for better DX when previewing pages
  // Preloads neighbor page assets and transition videos
  // Uses allPagesPreloadElements (extracted in loadData) for proper neighbor preloading
  const preloadOrchestrator = usePreloadOrchestrator({
    pages: pages.map((p) => ({
      id: p.id,
      background_image_url: p.background_image_url,
      background_video_url: p.background_video_url,
      background_audio_url: p.background_audio_url,
    })),
    pageLinks,
    elements: allPagesPreloadElements, // Use elements from ALL pages for proper neighbor preloading
    currentPageId: activePageId,
    enabled: !isLoading && !!activePageId,
    // maxNeighborDepth defaults to 1 - only preload immediate neighbors
  });

  // Page switch hook for smooth background transitions (uses blob URLs from preload cache)
  const pageSwitch = usePageSwitch({
    preloadCache: preloadOrchestrator
      ? {
          getReadyBlobUrl: preloadOrchestrator.getReadyBlobUrl,
          getCachedBlobUrl: preloadOrchestrator.getCachedBlobUrl,
          preloadedUrls: preloadOrchestrator.preloadedUrls,
        }
      : undefined,
  });

  // Helper to switch pages without flash
  // Uses usePageSwitch hook to resolve blob URLs from preload cache
  // Also updates storage path state for editing/saving purposes
  const switchToPage = useCallback(
    async (page: TourPage | null) => {
      // Mark this page as initialized to prevent redundant effect calls
      if (page) {
        lastInitializedPageIdRef.current = page.id;
      }

      // Update storage path state (for editing and saving)
      setBackgroundImageUrl(page?.background_image_url || '');
      setBackgroundVideoUrl(page?.background_video_url || '');
      setBackgroundAudioUrl(page?.background_audio_url || '');

      // Use hook to resolve and set blob URLs for display
      await pageSwitch.switchToPage(
        page
          ? {
              id: page.id,
              background_image_url: page.background_image_url,
              background_video_url: page.background_video_url,
              background_audio_url: page.background_audio_url,
            }
          : null,
        () => {
          if (page) {
            setActivePageId(page.id);
          }
        },
      );
    },
    [pageSwitch],
  );

  const { isBuffering: isReverseBuffering } = useTransitionPlayback({
    videoRef: transitionVideoRef,
    transition: transitionPreview
      ? {
          videoUrl: resolveAssetPlaybackUrl(transitionPreview.videoUrl),
          storageKey: transitionPreview.storageKey,
          reverseMode: transitionPreview.reverseMode,
          reverseVideoUrl: transitionPreview.reverseVideoUrl
            ? resolveAssetPlaybackUrl(transitionPreview.reverseVideoUrl)
            : undefined,
          durationSec: transitionPreview.durationSec,
          targetPageId: pendingNavigationPageId || undefined,
          displayName: transitionPreview.title,
        }
      : null,
    onComplete: async (targetPageId) => {
      const video = transitionVideoRef.current;
      if (targetPageId) {
        const targetPage = pages.find((p) => p.id === targetPageId) || null;
        // Use switchToPage which resolves blob URLs via usePageSwitch
        await switchToPage(targetPage);
        clearSelection();
        setSelectedMenuItem('none');
        setErrorMessage('');
        requestAnimationFrame(() => {
          requestAnimationFrame(() => {
            video?.removeAttribute('src');
            video?.load();
            closeTransitionPreview();
          });
        });
      } else {
        video?.removeAttribute('src');
        video?.load();
        closeTransitionPreview();
      }
    },
    timeouts: {
      playbackStartMs: 3000,
      hardTimeoutMs: 45000,
    },
    features: {
      useBlobUrl: true,
      preDecodeImages: false, // We handle image loading via usePageSwitch
    },
    preload: {
      preloadedUrls: preloadOrchestrator.preloadedUrls,
      getCachedBlobUrl: preloadOrchestrator.getCachedBlobUrl,
      getReadyBlobUrl: preloadOrchestrator.getReadyBlobUrl,
    },
  });

  // Use shared background transition hook for direct navigation clearing
  // (No fade-out needed in constructor - transitions complete immediately)
  useBackgroundTransition({ pageSwitch });

  const iconPreloadTargets = useMemo(() => {
    const preloadableTypes: CanvasElementType[] = [
      'navigation_next',
      'navigation_prev',
      'tooltip',
      'description',
    ];
    const urls = elements
      .filter(
        (element) =>
          preloadableTypes.includes(element.type) && Boolean(element.iconUrl),
      )
      .map((element) => resolveAssetPlaybackUrl(element.iconUrl))
      .filter(Boolean);

    return Array.from(new Set(urls));
  }, [elements]);

  // Icon preloading for smooth rendering
  const { preloadedUrlMap: preloadedIconUrlMap } = useIconPreload({
    iconUrls: iconPreloadTargets,
    enabled: !isLoading,
  });

  const imageAssetOptions = useMemo(
    () =>
      assets
        .filter(
          (asset) => asset.asset_type === 'image' && getAssetSourceValue(asset),
        )
        .map((asset) => ({
          value: getAssetSourceValue(asset),
          label: getAssetLabel(asset),
        })),
    [assets],
  );
  const backgroundImageAssetOptions = useMemo(
    () =>
      assets
        .filter(
          (asset) =>
            asset.asset_type === 'image' &&
            getAssetSourceValue(asset) &&
            isBackgroundImageAsset(asset),
        )
        .map((asset) => ({
          value: getAssetSourceValue(asset),
          label: getAssetLabel(asset),
        })),
    [assets],
  );
  const videoAssetOptions = useMemo(
    () =>
      assets
        .filter(
          (asset) =>
            asset.asset_type === 'video' &&
            asset.type !== 'transition' &&
            getAssetSourceValue(asset),
        )
        .map((asset) => ({
          value: getAssetSourceValue(asset),
          label: getAssetLabel(asset),
        })),
    [assets],
  );
  const audioAssetOptions = useMemo(
    () =>
      assets
        .filter(
          (asset) => asset.asset_type === 'audio' && getAssetSourceValue(asset),
        )
        .map((asset) => ({
          value: getAssetSourceValue(asset),
          label: getAssetLabel(asset),
        })),
    [assets],
  );
  const transitionVideoAssetOptions = useMemo(() => {
    const typedAssets = assets
      .filter(
        (asset) =>
          asset.type === 'transition' &&
          asset.asset_type === 'video' &&
          getAssetSourceValue(asset),
      )
      .map((asset) => ({
        value: getAssetSourceValue(asset),
        label: getAssetLabel(asset),
      }));

    if (typedAssets.length > 0) return typedAssets;

    const taggedAssets = assets
      .filter(
        (asset) =>
          asset.asset_type === 'video' &&
          getAssetSourceValue(asset) &&
          /\[TRANSITION\]/i.test(String(asset.name || '')),
      )
      .map((asset) => ({
        value: getAssetSourceValue(asset),
        label: getAssetLabel(asset),
      }));

    return taggedAssets;
  }, [assets]);
  const iconAssetOptions = useMemo(
    () =>
      assets
        .filter(
          (asset) =>
            asset.type === 'icon' &&
            asset.asset_type === 'image' &&
            getAssetSourceValue(asset),
        )
        .map((asset) => ({
          value: getAssetSourceValue(asset),
          label: getAssetLabel(asset),
        })),
    [assets],
  );
  // Media duration probing with caching
  const durationProbeTargets = useMemo(
    () =>
      buildDurationProbeTargets({
        backgroundVideoUrl,
        backgroundAudioUrl,
        selectedElement,
        newTransitionVideoUrl,
        elements,
        isMediaElementType,
        isVideoPlayerElementType,
        isNavigationElementType,
      }),
    [
      backgroundAudioUrl,
      backgroundVideoUrl,
      elements,
      newTransitionVideoUrl,
      selectedElement,
    ],
  );

  const { getDuration, getDurationNote } = useMediaDurationProbe({
    targets: durationProbeTargets,
  });

  const backgroundVideoDurationNote = getDurationNote(backgroundVideoUrl);
  const backgroundAudioDurationNote = getDurationNote(backgroundAudioUrl);
  const selectedMediaDurationNote = useMemo(() => {
    if (!selectedElement || !isMediaElementType(selectedElement.type)) {
      return 'Duration: unknown';
    }
    return getDurationNote(selectedElement.mediaUrl || '');
  }, [getDurationNote, selectedElement]);

  const newTransitionDurationNote = getDurationNote(newTransitionVideoUrl);

  const selectedTransitionDurationNote = useMemo(() => {
    if (!selectedElement || !isNavigationElementType(selectedElement.type)) {
      return 'Duration: unknown';
    }
    return getDurationNote(selectedElement.transitionVideoUrl || '');
  }, [getDurationNote, selectedElement]);

  useEffect(() => {
    if (newTransitionVideoUrl) return;
    if (!transitionVideoAssetOptions.length) return;
    setNewTransitionVideoUrl(transitionVideoAssetOptions[0].value);
  }, [newTransitionVideoUrl, transitionVideoAssetOptions]);

  useEffect(() => {
    setElements((prev) => {
      let hasChanges = false;
      const next = prev.map((element) => {
        if (!isNavigationElementType(element.type)) return element;

        const resolvedDuration = getDuration(element.transitionVideoUrl || '');
        const nextDuration =
          Number.isFinite(resolvedDuration) && Number(resolvedDuration) > 0
            ? Number(resolvedDuration)
            : undefined;
        if (element.transitionDurationSec === nextDuration) return element;

        hasChanges = true;
        return {
          ...element,
          transitionDurationSec: nextDuration,
        };
      });

      return hasChanges ? next : prev;
    });
  }, [getDuration]);

  const loadData = useCallback(
    async (preservePageId?: string) => {
      if (!projectId || !router.isReady || !isAuthReady) return;

      try {
        setIsLoading(true);
        setErrorMessage('');
        setSuccessMessage('');

        const [
          projectResponse,
          pagesResponse,
          assetsResponse,
          uiElementsResponse,
        ] = await Promise.all([
          axios.get(`/projects/${projectId}`),
          axios.get(
            `/tour_pages?limit=500&sort=asc&field=sort_order&project=${projectId}&environment=dev`,
          ),
          axios.get(
            `/assets?limit=500&page=0&sort=desc&field=createdAt&projectId=${projectId}`,
          ),
          axios.get(
            `/project-element-defaults?projectId=${projectId}&limit=200&page=0&sort=asc&field=sort_order`,
          ),
        ]);

        const pageRows: TourPage[] = Array.isArray(pagesResponse?.data?.rows)
          ? pagesResponse.data.rows
          : [];
        const assetRows: ProjectAsset[] = Array.isArray(
          assetsResponse?.data?.rows,
        )
          ? assetsResponse.data.rows
          : [];
        setProjectName(projectResponse?.data?.name || '');
        setPages(pageRows);

        // Extract page links and preload elements using shared utility
        const {
          pageLinks: syntheticPageLinks,
          preloadElements: allPreloadElements,
        } = extractPageLinksAndElements(pageRows);

        setPageLinks(syntheticPageLinks);
        setAllPagesPreloadElements(allPreloadElements);
        setAssets(assetRows);

        // Process project element defaults using shared utilities
        const uiElementRows = Array.isArray(uiElementsResponse?.data?.rows)
          ? uiElementsResponse.data.rows
          : [];
        const normalizedDefaults = uiElementRows
          .map((row: Record<string, unknown>) => normalizeElementDefault(row))
          .filter(
            (
              d: NormalizedElementDefault | null,
            ): d is NormalizedElementDefault => d !== null,
          );
        const defaultsByType = buildElementDefaultsMap(normalizedDefaults);
        setUiElementDefaultsByType(defaultsByType);

        // Preserve current page if specified and it still exists, otherwise use route or first page
        const preservedPageExists =
          preservePageId && pageRows.some((p: any) => p.id === preservePageId);
        const defaultPageId = preservedPageExists
          ? preservePageId
          : pageIdFromRoute || pageRows[0]?.id || '';
        setActivePageId(defaultPageId);
        setIsMenuOpen(false);
      } catch (error: any) {
        if (error?.response?.status === 401) {
          const message = 'Your session has expired. Please sign in again.';
          logger.error(
            'Unauthorized constructor request:',
            error instanceof Error ? error : { error },
          );
          setErrorMessage(message);
          setPages([]);
          setAssets([]);
          router.replace('/login');
          return;
        }

        const message =
          error?.response?.data?.message ||
          error?.message ||
          'Failed to load constructor data.';
        logger.error(
          'Failed to load constructor data:',
          error instanceof Error ? error : { error },
        );
        setErrorMessage(message);
        setPages([]);
        setAssets([]);
        setUiElementDefaultsByType({});
      } finally {
        setIsLoading(false);
      }
    },
    [isAuthReady, pageIdFromRoute, projectId, router],
  );

  // Page actions (save, create page, save to stage)
  const {
    isSaving,
    isSavingToStage,
    isCreatingPage,
    isCreatingTransition,
    saveConstructor,
    saveToStage,
    createPage,
    createTransition,
  } = useConstructorPageActions({
    projectId,
    pages,
    activePage,
    activePageId,
    elements,
    backgroundImageUrl,
    backgroundVideoUrl,
    backgroundAudioUrl,
    onReload: loadData,
    onSetActivePageId: setActivePageId,
    onSetMenuOpen: setIsMenuOpen,
    onError: setErrorMessage,
    onSuccess: setSuccessMessage,
  });

  useEffect(() => {
    if (!router.isReady || typeof window === 'undefined') return;

    const token =
      sessionStorage.getItem('token') || localStorage.getItem('token');
    if (!token) {
      setIsAuthReady(false);
      setErrorMessage('Please sign in to continue.');
      router.replace('/login');
      return;
    }

    setIsAuthReady(true);
  }, [router]);

  useEffect(() => {
    if (!router.isReady) return;
    if (projectId) return;
    router.replace(
      isElementEditMode
        ? '/project-element-defaults/project-element-defaults-list'
        : '/projects/projects-list',
    );
  }, [isElementEditMode, projectId, router]);

  useEffect(() => {
    loadData();
  }, [loadData]);

  // Panel initial positions are handled by useDraggable hooks

  useEffect(() => {
    if (!router.isReady || !isAuthReady || isLoading) return;
    if (didSetInitialCanvasFocus.current) return;
    if (!canvasRef.current) return;

    didSetInitialCanvasFocus.current = true;
    requestAnimationFrame(() => {
      canvasRef.current?.focus({ preventScroll: true });
    });
  }, [isAuthReady, isLoading, router.isReady]);

  useEffect(() => {
    if (!activePage) {
      setElements([]);
      clearSelection();
      setBackgroundImageUrl('');
      setBackgroundVideoUrl('');
      setBackgroundAudioUrl('');
      return;
    }

    const schema = parseJsonObject<ConstructorSchema>(
      activePage.ui_schema_json,
      {},
    );
    const normalizedElements = Array.isArray(schema.elements)
      ? schema.elements
          .filter(
            (item) =>
              item && item.type && labelByType[item.type as CanvasElementType],
          )
          .map((item) => {
            const elementType = item.type as CanvasElementType;
            const normalizedElement: CanvasElement = {
              ...item,
              id: String(item.id || createLocalId()),
              label:
                typeof item.label === 'string' && item.label.trim()
                  ? item.label
                  : labelByType[elementType],
              xPercent: clamp(Number(item.xPercent || 0), 0, 100),
              yPercent: clamp(Number(item.yPercent || 0), 0, 100),
              appearDelaySec: normalizeAppearDelaySec(item.appearDelaySec),
              appearDurationSec: normalizeAppearDurationSec(
                item.appearDurationSec,
              ),
              galleryCards: Array.isArray(item.galleryCards)
                ? item.galleryCards.map((card: any, index: number) => ({
                    id: String(card?.id || createLocalId()),
                    imageUrl: String(card?.imageUrl || ''),
                    title: String(card?.title || `Card ${index + 1}`),
                    description: String(card?.description || ''),
                  }))
                : undefined,
              galleryHeaderImageUrl:
                typeof item.galleryHeaderImageUrl === 'string'
                  ? item.galleryHeaderImageUrl
                  : undefined,
              galleryTitle:
                typeof item.galleryTitle === 'string'
                  ? item.galleryTitle
                  : undefined,
              galleryInfoSpans: Array.isArray(item.galleryInfoSpans)
                ? item.galleryInfoSpans.map((span: any) => ({
                    id: String(span?.id || createLocalId()),
                    text: String(span?.text || ''),
                  }))
                : undefined,
              galleryColumns:
                typeof item.galleryColumns === 'number'
                  ? item.galleryColumns
                  : undefined,
              carouselSlides: Array.isArray(item.carouselSlides)
                ? item.carouselSlides.map((slide: any, index: number) => ({
                    id: String(slide?.id || createLocalId()),
                    imageUrl: String(slide?.imageUrl || ''),
                    caption: String(slide?.caption || `Slide ${index + 1}`),
                  }))
                : undefined,
              iconUrl: typeof item.iconUrl === 'string' ? item.iconUrl : '',
              carouselPrevIconUrl:
                typeof item.carouselPrevIconUrl === 'string'
                  ? item.carouselPrevIconUrl
                  : '',
              carouselNextIconUrl:
                typeof item.carouselNextIconUrl === 'string'
                  ? item.carouselNextIconUrl
                  : '',
              // Gallery Carousel Settings
              galleryCarouselPrevIconUrl:
                typeof item.galleryCarouselPrevIconUrl === 'string'
                  ? item.galleryCarouselPrevIconUrl
                  : '',
              galleryCarouselNextIconUrl:
                typeof item.galleryCarouselNextIconUrl === 'string'
                  ? item.galleryCarouselNextIconUrl
                  : '',
              galleryCarouselBackIconUrl:
                typeof item.galleryCarouselBackIconUrl === 'string'
                  ? item.galleryCarouselBackIconUrl
                  : '',
              galleryCarouselBackLabel:
                typeof item.galleryCarouselBackLabel === 'string'
                  ? item.galleryCarouselBackLabel
                  : '',
              galleryCarouselPrevX:
                typeof item.galleryCarouselPrevX === 'number'
                  ? item.galleryCarouselPrevX
                  : undefined,
              galleryCarouselPrevY:
                typeof item.galleryCarouselPrevY === 'number'
                  ? item.galleryCarouselPrevY
                  : undefined,
              galleryCarouselNextX:
                typeof item.galleryCarouselNextX === 'number'
                  ? item.galleryCarouselNextX
                  : undefined,
              galleryCarouselNextY:
                typeof item.galleryCarouselNextY === 'number'
                  ? item.galleryCarouselNextY
                  : undefined,
              galleryCarouselBackX:
                typeof item.galleryCarouselBackX === 'number'
                  ? item.galleryCarouselBackX
                  : undefined,
              galleryCarouselBackY:
                typeof item.galleryCarouselBackY === 'number'
                  ? item.galleryCarouselBackY
                  : undefined,
              tooltipTitle:
                typeof item.tooltipTitle === 'string' ? item.tooltipTitle : '',
              tooltipText:
                typeof item.tooltipText === 'string' ? item.tooltipText : '',
              descriptionTitle:
                typeof item.descriptionTitle === 'string'
                  ? item.descriptionTitle
                  : '',
              descriptionText:
                typeof item.descriptionText === 'string'
                  ? item.descriptionText
                  : '',
              navLabel: typeof item.navLabel === 'string' ? item.navLabel : '',
              navType:
                item.navType === 'back' || item.navType === 'forward'
                  ? item.navType
                  : isNavigationElementType(elementType)
                    ? getNavigationButtonKind(
                        elementType as NavigationElementType,
                      )
                    : undefined,
              // Support both targetPageSlug (new) and targetPageId (legacy)
              targetPageSlug:
                typeof item.targetPageSlug === 'string'
                  ? item.targetPageSlug
                  : '',
              targetPageId:
                typeof item.targetPageId === 'string' ? item.targetPageId : '',
              transitionVideoUrl:
                typeof item.transitionVideoUrl === 'string'
                  ? item.transitionVideoUrl
                  : '',
              transitionReverseMode:
                item.transitionReverseMode === 'separate_video'
                  ? 'separate_video'
                  : ('auto_reverse' as const),
              reverseVideoUrl:
                typeof item.reverseVideoUrl === 'string'
                  ? item.reverseVideoUrl
                  : '',
              transitionDurationSec: item.transitionDurationSec
                ? Number(item.transitionDurationSec)
                : undefined,
              mediaUrl: typeof item.mediaUrl === 'string' ? item.mediaUrl : '',
              mediaAutoplay:
                typeof item.mediaAutoplay === 'boolean'
                  ? item.mediaAutoplay
                  : true,
              mediaLoop:
                typeof item.mediaLoop === 'boolean' ? item.mediaLoop : true,
              mediaMuted:
                typeof item.mediaMuted === 'boolean'
                  ? item.mediaMuted
                  : isVideoPlayerElementType(item.type),
            };

            return mergeElementWithDefaults(
              normalizedElement,
              uiElementDefaultsByType[elementType],
              { preferElementValues: true },
            );
          })
      : [];

    setElements(normalizedElements);
    setSelectedMenuItem('none');

    const currentSelectedId = selectedElementIdRef.current;
    if (!normalizedElements.length) {
      clearSelection();
    } else if (
      elementIdFromRoute &&
      normalizedElements.some((element) => element.id === elementIdFromRoute)
    ) {
      selectElement(elementIdFromRoute);
    } else if (
      currentSelectedId &&
      !normalizedElements.some((element) => element.id === currentSelectedId)
    ) {
      // Current selection no longer valid
      clearSelection();
    }
    // If current selection is still valid, do nothing (keep current)
    // Set storage paths for editing/saving
    setBackgroundImageUrl(activePage.background_image_url || '');
    setBackgroundVideoUrl(activePage.background_video_url || '');
    setBackgroundAudioUrl(activePage.background_audio_url || '');
    // Resolve blob URLs via hook for display (handles initial load and route changes)
    // Only call if this page wasn't already initialized via switchToPage function
    if (lastInitializedPageIdRef.current !== activePage.id) {
      lastInitializedPageIdRef.current = activePage.id;
      pageSwitch.switchToPage({
        id: activePage.id,
        background_image_url: activePage.background_image_url,
        background_video_url: activePage.background_video_url,
        background_audio_url: activePage.background_audio_url,
      });
    }
  }, [
    activePage,
    elementIdFromRoute,
    uiElementDefaultsByType,
    pageSwitch.switchToPage,
    clearSelection,
    selectElement,
    setElements,
  ]);

  useEffect(() => {
    if (allowedNavigationTypes.length !== 1) return;
    const forcedType = allowedNavigationTypes[0];

    setElements((prev) => {
      let hasChanges = false;
      const nextElements = prev.map((element) => {
        if (
          !isNavigationElementType(element.type) ||
          element.type === forcedType
        )
          return element;
        hasChanges = true;
        return normalizeNavigationType(element, forcedType);
      });
      return hasChanges ? nextElements : prev;
    });
  }, [allowedNavigationTypes, normalizeNavigationType, setElements]);

  // Element drag is now handled by useCanvasElementDrag hook

  useEffect(() => {
    if (isConstructorEditMode) return;
    cancelElementDrag();
    clearSelection();
    setSelectedMenuItem('none');
  }, [isConstructorEditMode, cancelElementDrag, clearSelection]);

  // Outside click detection to clear element/menu selection
  useOutsideClick({
    containerRef: elementEditorRef,
    ignoreDataAttribute: 'data-constructor-element-id',
    selectedValue: selectedElementId,
    onOutsideClick: useCallback(() => {
      clearSelection();
      setSelectedMenuItem('none');
    }, [clearSelection]),
    enabled:
      isConstructorEditMode &&
      (!!selectedElementId || selectedMenuItem !== 'none'),
  });

  // Thin wrappers for hook functions (handle additional state like selectedMenuItem)
  const selectElementForEdit = useCallback(
    (elementId: string) => {
      selectElement(elementId);
      // Note: setSelectedMenuItem('none') is handled by onElementSelected callback
    },
    [selectElement],
  );

  const selectMenuItemForEdit = useCallback(
    (item: EditorMenuItem) => {
      clearSelection();
      setSelectedMenuItem(item);
    },
    [clearSelection],
  );

  // createPage, saveConstructor, saveToStage are now provided by useConstructorPageActions hook

  const onElementMouseDown = (event: React.MouseEvent, elementId: string) => {
    if (!isConstructorEditMode) return;

    const currentElement = elements.find((item) => item.id === elementId);
    if (!currentElement) return;

    // Select the element for editing
    selectElementForEdit(elementId);

    // Start drag with current position
    onElementDragStart(
      event,
      elementId,
      currentElement.xPercent,
      currentElement.yPercent,
    );
  };

  // openTransitionPreviewForElement is now provided by useTransitionPreview hook

  const openTransitionPreview = (direction: 'forward' | 'back') => {
    if (
      !selectedElement ||
      (selectedElement.type !== 'navigation_next' &&
        selectedElement.type !== 'navigation_prev')
    ) {
      return;
    }

    openTransitionPreviewForElement(selectedElement, direction);
  };

  const onCanvasElementClick = (element: CanvasElement) => {
    if (!isConstructorEditMode) {
      if (isNavigationElementType(element.type)) {
        // Disable navigation while transition is playing or buffering
        if (transitionPreview || isReverseBuffering) {
          return;
        }
        if (element.navDisabled) {
          return;
        }

        // Use shared navigation helpers
        const direction = getNavigationDirection(element);
        const navTarget = resolveNavigationTarget(element, pages);

        if (!navTarget) {
          setErrorMessage(
            'No target page configured for this navigation button.',
          );
          return;
        }

        // Check if transition can be played using shared helper
        if (!hasPlayableTransition(element, direction)) {
          closeTransitionPreview();
          // Use switchToPage which resolves blob URLs via usePageSwitch (reduces flash)
          switchToPage(navTarget.page).then(() => {
            clearSelection();
            setSelectedMenuItem('none');
            setErrorMessage('');
          });
          return;
        }

        openPreviewWithTarget(element, direction, navTarget.pageId);
      }
      return;
    }

    selectElementForEdit(element.id);
  };

  // Handler for gallery card clicks
  const handleGalleryCardClick = useCallback(
    (element: CanvasElement, cardIndex: number) => {
      if (element.galleryCards && element.galleryCards.length > 0) {
        setActiveGalleryCarousel({ element, initialIndex: cardIndex });
      }
    },
    [],
  );

  // Handler for gallery carousel button position changes (constructor only)
  const handleCarouselButtonPositionChange = useCallback(
    (button: 'prev' | 'next' | 'back', x: number, y: number) => {
      if (!activeGalleryCarousel) return;

      const positionPatch =
        button === 'prev'
          ? { galleryCarouselPrevX: x, galleryCarouselPrevY: y }
          : button === 'next'
            ? { galleryCarouselNextX: x, galleryCarouselNextY: y }
            : { galleryCarouselBackX: x, galleryCarouselBackY: y };

      updateSelectedElement(positionPatch);

      // Update the active carousel element to reflect the new positions
      setActiveGalleryCarousel((prev) =>
        prev ? { ...prev, element: { ...prev.element, ...positionPatch } } : null,
      );
    },
    [activeGalleryCarousel, updateSelectedElement],
  );

  const isElementVisibleOnCanvas = (element: CanvasElement) =>
    isElementVisibleAtTime(
      canvasElapsedSec,
      element.appearDelaySec,
      element.appearDurationSec,
    );

  const isElementReadyForCanvasRender = (element: CanvasElement) => {
    const isPreloadableIconElement =
      (isNavigationElementType(element.type) ||
        isTooltipElementType(element.type) ||
        isDescriptionElementType(element.type)) &&
      Boolean(element.iconUrl);

    if (!isPreloadableIconElement) return true;

    const playbackUrl = resolveAssetPlaybackUrl(element.iconUrl);
    if (!playbackUrl) return true;

    return Boolean(preloadedIconUrlMap[playbackUrl]);
  };

  // URL resolver that uses preloaded blob URLs when available
  const resolveUrlWithBlob = useCallback(
    (url: string | undefined): string => {
      if (!url) return '';

      // Try to get blob URL from preload orchestrator (instant display)
      // Check storage key first (most reliable), then resolved URL
      const blobUrl =
        preloadOrchestrator.getReadyBlobUrl(url) ||
        preloadOrchestrator.getReadyBlobUrl(resolveAssetPlaybackUrl(url));
      if (blobUrl) return blobUrl;

      // Fall back to standard resolution
      return resolveAssetPlaybackUrl(url);
    },
    [preloadOrchestrator],
  );

  const canvasBackgroundStyle: React.CSSProperties = {};
  // Prefer hook's blob URLs, then try cached blob URLs, finally fall back to direct URLs
  const backgroundImageSrc =
    pageSwitch.currentBgImageUrl || resolveUrlWithBlob(backgroundImageUrl);
  const backgroundVideoSrc =
    pageSwitch.currentBgVideoUrl || resolveUrlWithBlob(backgroundVideoUrl);
  const backgroundAudioSrc =
    pageSwitch.currentBgAudioUrl || resolveUrlWithBlob(backgroundAudioUrl);

  const hasEditorSelection =
    isConstructorEditMode &&
    (Boolean(selectedElement) || selectedMenuItem !== 'none');
  const editorTitle =
    selectedMenuItem === 'background_image'
      ? 'Background image'
      : selectedMenuItem === 'background_video'
        ? 'Background video'
        : selectedMenuItem === 'background_audio'
          ? 'Background audio'
          : selectedMenuItem === 'create_transition'
            ? 'Create transition'
            : selectedElement?.label || 'Element editor';

  if (backgroundImageSrc) {
    canvasBackgroundStyle.backgroundImage = `url("${backgroundImageSrc}")`;
    canvasBackgroundStyle.backgroundSize = 'cover';
    canvasBackgroundStyle.backgroundPosition = 'center';
  }

  return (
    <>
      <Head>
        <title>
          {getPageTitle(isElementEditMode ? 'Edit Element' : 'Constructor')}
        </title>
      </Head>
      <div className='relative w-screen h-screen bg-black overflow-hidden'>
        <div className='absolute top-4 left-4 z-30 flex max-w-[80vw] flex-col gap-2'>
          <p className='text-xs font-semibold text-gray-700'>
            {projectName || 'Loading project...'}
          </p>
          {errorMessage ? (
            <p className='rounded bg-red-50 px-2 py-1 text-xs text-red-600'>
              {errorMessage}
            </p>
          ) : null}
          {successMessage ? (
            <p className='rounded bg-green-50 px-2 py-1 text-xs text-green-700'>
              {successMessage}
            </p>
          ) : null}

          {pages.length > 0 && isElementEditMode && (
            <div className='flex items-center gap-2'>
              <BaseButton
                color='lightDark'
                label='Back to Elements'
                icon={mdiExitToApp}
                href={pageElementsListHref}
              />
              <BaseButton
                color='info'
                label={isSaving ? 'Saving...' : 'Save'}
                icon={mdiContentSave}
                onClick={saveConstructor}
                disabled={isSaving}
              />
            </div>
          )}
        </div>

        {pages.length > 0 && !isElementEditMode && (
          <ConstructorControlsPanel
            projectId={projectId}
            pages={pages}
            activePageId={activePageId}
            interactionMode={constructorInteractionMode}
            position={constructorControlsPosition}
            onPageChange={(pageId) => {
              const page = pages.find((p) => p.id === pageId);
              if (page) switchToPage(page);
            }}
            onModeChange={setConstructorInteractionMode}
            onDragStart={onConstructorControlsDragStart}
          />
        )}

        <div
          ref={canvasRef}
          tabIndex={-1}
          className='absolute inset-0 bg-black overflow-hidden'
          style={canvasBackgroundStyle}
        >
          <CanvasBackground
            backgroundImageUrl={backgroundImageSrc}
            backgroundVideoUrl={backgroundVideoSrc}
            backgroundAudioUrl={backgroundAudioSrc}
            previousBgImageUrl={pageSwitch.previousBgImageUrl}
            isSwitching={pageSwitch.isSwitching}
            isNewBgReady={pageSwitch.isNewBgReady}
            onBackgroundReady={() => pageSwitch.markBackgroundReady()}
          />

          {isLoading ? (
            <div className='absolute inset-0 flex items-center justify-center'>
              <p className='text-sm text-gray-500'>Loading constructor...</p>
            </div>
          ) : pages.length === 0 ? (
            <div className='absolute inset-0 flex items-center justify-center'>
              <BaseButton
                color='info'
                label={isCreatingPage ? 'Creating...' : 'Create First Page'}
                icon={mdiPlus}
                onClick={createPage}
                disabled={isCreatingPage}
              />
            </div>
          ) : (
            elements.map((element) => {
              const shouldRender =
                selectedElementId === element.id ||
                (isElementVisibleOnCanvas(element) &&
                  isElementReadyForCanvasRender(element));
              if (!shouldRender) return null;

              const isNavDisabled =
                isNavigationElementType(element.type) &&
                (element.navDisabled ||
                  Boolean(transitionPreview) ||
                  isReverseBuffering);

              return (
                <CanvasElementComponent
                  key={element.id}
                  element={element}
                  isSelected={selectedElementId === element.id}
                  isEditMode={isConstructorEditMode}
                  isDisabled={isNavDisabled}
                  onClick={() => onCanvasElementClick(element)}
                  onMouseDown={(event) => onElementMouseDown(event, element.id)}
                  resolveUrl={resolveUrlWithBlob}
                  onGalleryCardClick={(cardIndex) =>
                    handleGalleryCardClick(element, cardIndex)
                  }
                />
              );
            })
          )}
        </div>

        {pages.length > 0 && hasEditorSelection && (
          <ElementEditorPanel
            elementEditorRef={elementEditorRef}
            position={editorPosition}
            isCollapsed={isEditorCollapsed}
            onToggleCollapse={() => setIsEditorCollapsed((prev) => !prev)}
            onDragStart={onElementEditorDragStart}
            title={editorTitle}
            activeTab={elementEditorTab}
            onTabChange={setElementEditorTab}
            selectedElement={selectedElement}
            selectedMenuItem={selectedMenuItem}
            onRemoveElement={removeSelectedElement}
            onUpdateElement={updateSelectedElement}
            backgroundImageUrl={backgroundImageUrl}
            backgroundVideoUrl={backgroundVideoUrl}
            backgroundAudioUrl={backgroundAudioUrl}
            onBackgroundImageChange={setBackgroundImageUrl}
            onBackgroundVideoChange={setBackgroundVideoUrl}
            onBackgroundAudioChange={setBackgroundAudioUrl}
            newTransitionName={newTransitionName}
            newTransitionVideoUrl={newTransitionVideoUrl}
            newTransitionSupportsReverse={newTransitionSupportsReverse}
            isCreatingTransition={isCreatingTransition}
            onNewTransitionNameChange={setNewTransitionName}
            onNewTransitionVideoUrlChange={setNewTransitionVideoUrl}
            onNewTransitionSupportsReverseChange={
              setNewTransitionSupportsReverse
            }
            onCreateTransition={() =>
              createTransition({
                name: newTransitionName,
                videoUrl: newTransitionVideoUrl,
                supportsReverse: newTransitionSupportsReverse,
                durationSec: getDuration(newTransitionVideoUrl),
              })
            }
            backgroundVideoDurationNote={backgroundVideoDurationNote}
            backgroundAudioDurationNote={backgroundAudioDurationNote}
            newTransitionDurationNote={newTransitionDurationNote}
            selectedMediaDurationNote={selectedMediaDurationNote}
            selectedTransitionDurationNote={selectedTransitionDurationNote}
            backgroundImageAssetOptions={backgroundImageAssetOptions}
            videoAssetOptions={videoAssetOptions}
            audioAssetOptions={audioAssetOptions}
            transitionVideoAssetOptions={transitionVideoAssetOptions}
            iconAssetOptions={iconAssetOptions}
            imageAssetOptions={imageAssetOptions}
            allowedNavigationTypes={allowedNavigationTypes}
            pages={pages}
            activePageId={activePageId}
            onPreviewTransition={openTransitionPreview}
            galleryCards={galleryCards}
            galleryInfoSpans={galleryInfoSpans}
            carouselSlides={carouselSlides}
            normalizeNavigationType={normalizeNavigationType}
            getDuration={getDuration}
          />
        )}

        {pages.length > 0 && !isElementEditMode && (
          <ConstructorMenu
            position={menuPosition}
            isOpen={isMenuOpen}
            allowedNavigationTypes={allowedNavigationTypes}
            isCreatingPage={isCreatingPage}
            isSaving={isSaving}
            isSavingToStage={isSavingToStage}
            onDragStart={onMenuDragStart}
            onToggleOpen={() => setIsMenuOpen((prev) => !prev)}
            onSelectMenuItem={selectMenuItemForEdit}
            onAddElement={addElement}
            onCreatePage={createPage}
            onSave={saveConstructor}
            onSaveToStage={saveToStage}
            onExit={() =>
              router.push(
                projectId
                  ? `/projects/${projectId}`
                  : '/projects/projects-list',
              )
            }
          />
        )}
      </div>

      <TransitionPreviewOverlay
        videoRef={transitionVideoRef}
        isActive={Boolean(transitionPreview)}
        isBuffering={isReverseBuffering}
      />

      {/* Gallery Carousel Overlay */}
      {activeGalleryCarousel && (
        <GalleryCarouselOverlay
          cards={activeGalleryCarousel.element.galleryCards || []}
          initialIndex={activeGalleryCarousel.initialIndex}
          onClose={() => setActiveGalleryCarousel(null)}
          resolveUrl={resolveUrlWithBlob}
          prevIconUrl={
            activeGalleryCarousel.element.galleryCarouselPrevIconUrl
          }
          nextIconUrl={
            activeGalleryCarousel.element.galleryCarouselNextIconUrl
          }
          backIconUrl={
            activeGalleryCarousel.element.galleryCarouselBackIconUrl
          }
          backLabel={
            activeGalleryCarousel.element.galleryCarouselBackLabel || 'BACK'
          }
          prevX={activeGalleryCarousel.element.galleryCarouselPrevX}
          prevY={activeGalleryCarousel.element.galleryCarouselPrevY}
          nextX={activeGalleryCarousel.element.galleryCarouselNextX}
          nextY={activeGalleryCarousel.element.galleryCarouselNextY}
          backX={activeGalleryCarousel.element.galleryCarouselBackX}
          backY={activeGalleryCarousel.element.galleryCarouselBackY}
          prevWidth={activeGalleryCarousel.element.galleryCarouselPrevWidth}
          prevHeight={activeGalleryCarousel.element.galleryCarouselPrevHeight}
          nextWidth={activeGalleryCarousel.element.galleryCarouselNextWidth}
          nextHeight={activeGalleryCarousel.element.galleryCarouselNextHeight}
          backWidth={activeGalleryCarousel.element.galleryCarouselBackWidth}
          backHeight={activeGalleryCarousel.element.galleryCarouselBackHeight}
          isEditMode={isConstructorEditMode}
          onButtonPositionChange={handleCarouselButtonPositionChange}
        />
      )}

      <style jsx>{`
        .menu-action-btn {
          width: 100%;
          display: flex;
          align-items: center;
          gap: 8px;
          font-size: 12px;
          padding: 6px 8px;
          border-radius: 6px;
          color: #1f2937;
          text-align: left;
        }

        .menu-action-btn:hover {
          background: #f3f4f6;
        }
      `}</style>
    </>
  );
};

ConstructorPage.getLayout = function getLayout(page: ReactElement) {
  return <LayoutAuthenticated>{page}</LayoutAuthenticated>;
};

export default ConstructorPage;
