import {
  mdiArrowLeft,
  mdiContentSave,
  mdiPencil,
  mdiPlus,
  mdiTrashCan,
} from '@mdi/js';
import axios from 'axios';
import Head from 'next/head';
import Link from 'next/link';
import { useRouter } from 'next/router';
import React, {
  ReactElement,
  useCallback,
  useEffect,
  useMemo,
  useState,
} from 'react';
import BaseButton from '../../components/BaseButton';
import CardBox from '../../components/CardBox';
import FormField from '../../components/FormField';
import SectionMain from '../../components/SectionMain';
import SectionTitleLineWithButton from '../../components/SectionTitleLineWithButton';
import { getPageTitle } from '../../config';
import { hasPermission } from '../../helpers/userPermissions';
import { useAppSelector } from '../../stores/hooks';
import { logger } from '../../lib/logger';

type TourPage = {
  id: string;
  name?: string;
  slug?: string;
  sort_order?: number;
  environment?: string;
  source_key?: string;
  requires_auth?: boolean;
  ui_schema_json?: Record<string, any> | string;
  background_image_url?: string;
  background_video_url?: string;
  background_audio_url?: string;
  background_loop?: boolean;
};

type GalleryCard = {
  id: string;
  imageUrl: string;
  title: string;
  description: string;
};

type CarouselSlide = {
  id: string;
  imageUrl: string;
  caption: string;
};

type ConstructorElement = {
  id: string;
  type: string;
  label?: string;
  xPercent?: number;
  yPercent?: number;
  width?: string;
  height?: string;
  minWidth?: string;
  maxWidth?: string;
  minHeight?: string;
  maxHeight?: string;
  margin?: string;
  padding?: string;
  gap?: string;
  fontSize?: string;
  lineHeight?: string;
  fontWeight?: string;
  border?: string;
  borderRadius?: string;
  opacity?: string;
  boxShadow?: string;
  display?: string;
  position?: string;
  justifyContent?: string;
  alignItems?: string;
  textAlign?: string;
  zIndex?: string;
  appearDelaySec?: number;
  appearDurationSec?: number | null;
  iconUrl?: string;
  navLabel?: string;
  navType?: 'forward' | 'back';
  navDisabled?: boolean;
  targetPageId?: string;
  transitionVideoUrl?: string;
  transitionReverseMode?: 'auto_reverse' | 'separate_video';
  reverseVideoUrl?: string;
  transitionDurationSec?: number;
  tooltipTitle?: string;
  tooltipText?: string;
  descriptionTitle?: string;
  descriptionText?: string;
  descriptionTitleFontSize?: string;
  descriptionTextFontSize?: string;
  descriptionTitleFontFamily?: string;
  descriptionTextFontFamily?: string;
  descriptionTitleColor?: string;
  descriptionTextColor?: string;
  descriptionBackgroundColor?: string;
  mediaUrl?: string;
  mediaAutoplay?: boolean;
  mediaLoop?: boolean;
  mediaMuted?: boolean;
  carouselPrevIconUrl?: string;
  carouselNextIconUrl?: string;
  galleryCards?: GalleryCard[];
  carouselSlides?: CarouselSlide[];
};

type ConstructorSchema = {
  elements?: ConstructorElement[];
};

const parseJsonObject = <T,>(value?: unknown, fallback?: T): T => {
  if (!value) return (fallback || ({} as T)) as T;

  try {
    if (typeof value === 'string') {
      const parsed = JSON.parse(value);
      return (parsed || fallback || {}) as T;
    }

    if (typeof value === 'object') {
      return value as T;
    }

    return (fallback || ({} as T)) as T;
  } catch (error) {
    logger.error(
      'Failed to parse JSON on element edit page:',
      error instanceof Error ? error : { error },
    );
    return (fallback || ({} as T)) as T;
  }
};

const toStringQuery = (value: string | string[] | undefined) => {
  if (Array.isArray(value)) return String(value[0] || '').trim();
  return String(value || '').trim();
};

const clampPercent = (value: string) => {
  const parsed = Number(value);
  if (!Number.isFinite(parsed)) return 0;
  return Math.min(Math.max(parsed, 0), 100);
};

const parseNullableNumber = (value: string) => {
  if (!value.trim()) return null;
  const parsed = Number(value);
  if (!Number.isFinite(parsed) || parsed < 0) return null;
  return parsed;
};

const extractNumericValue = (value: unknown) => {
  const normalized = String(value ?? '').trim();
  if (!normalized) return '';
  const matched = normalized.match(/-?\d*\.?\d+/);
  return matched ? matched[0] : '';
};

const normalizeNumberString = (value: string) => {
  const normalized = String(value || '').trim();
  if (!normalized) return '';
  const parsed = Number(normalized);
  if (!Number.isFinite(parsed)) return '';
  return String(parsed);
};

const toOptionalTrimmed = (value: string) => {
  const normalized = String(value || '').trim();
  return normalized ? normalized : undefined;
};

const toUnitValue = (value: string, unit: 'vw' | 'vh' | 'px') => {
  const normalized = normalizeNumberString(value);
  return normalized ? `${normalized}${unit}` : undefined;
};

const createLocalId = () => {
  if (typeof window !== 'undefined' && window.crypto?.randomUUID) {
    return window.crypto.randomUUID();
  }

  return `element_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
};

const PageElementsProjectEditPage = () => {
  const router = useRouter();
  const { currentUser } = useAppSelector((state) => state.auth);
  const hasUpdatePermission = hasPermission(
    currentUser,
    'UPDATE_PAGE_ELEMENTS',
  );

  const projectId = useMemo(
    () => toStringQuery(router.query.projectId),
    [router.query.projectId],
  );
  const pageId = useMemo(
    () => toStringQuery(router.query.pageId),
    [router.query.pageId],
  );
  const elementId = useMemo(
    () => toStringQuery(router.query.elementId),
    [router.query.elementId],
  );

  const [currentPage, setCurrentPage] = useState<TourPage | null>(null);
  const [element, setElement] = useState<ConstructorElement | null>(null);
  const [projectPages, setProjectPages] = useState<TourPage[]>([]);
  const [isLoading, setIsLoading] = useState(false);
  const [isSaving, setIsSaving] = useState(false);
  const [errorMessage, setErrorMessage] = useState('');
  const [successMessage, setSuccessMessage] = useState('');

  const [label, setLabel] = useState('');
  const [xPercent, setXPercent] = useState('0');
  const [yPercent, setYPercent] = useState('0');
  const [width, setWidth] = useState('');
  const [height, setHeight] = useState('');
  const [minWidth, setMinWidth] = useState('');
  const [maxWidth, setMaxWidth] = useState('');
  const [minHeight, setMinHeight] = useState('');
  const [maxHeight, setMaxHeight] = useState('');
  const [margin, setMargin] = useState('');
  const [padding, setPadding] = useState('');
  const [gap, setGap] = useState('');
  const [fontSize, setFontSize] = useState('');
  const [lineHeight, setLineHeight] = useState('');
  const [fontWeight, setFontWeight] = useState('');
  const [border, setBorder] = useState('');
  const [borderRadius, setBorderRadius] = useState('');
  const [opacity, setOpacity] = useState('');
  const [boxShadow, setBoxShadow] = useState('');
  const [display, setDisplay] = useState('');
  const [position, setPosition] = useState('');
  const [justifyContent, setJustifyContent] = useState('');
  const [alignItems, setAlignItems] = useState('');
  const [textAlign, setTextAlign] = useState('');
  const [zIndex, setZIndex] = useState('');
  const [appearDelaySec, setAppearDelaySec] = useState('0');
  const [appearDurationSec, setAppearDurationSec] = useState('');
  const [iconUrl, setIconUrl] = useState('');
  const [navLabel, setNavLabel] = useState('');
  const [navType, setNavType] = useState<'forward' | 'back'>('forward');
  const [navDisabled, setNavDisabled] = useState(false);
  const [targetPageId, setTargetPageId] = useState('');
  const [transitionVideoUrl, setTransitionVideoUrl] = useState('');
  const [transitionReverseMode, setTransitionReverseMode] = useState<
    'auto_reverse' | 'separate_video'
  >('auto_reverse');
  const [reverseVideoUrl, setReverseVideoUrl] = useState('');
  const [transitionDurationSec, setTransitionDurationSec] = useState('0.7');
  const [tooltipTitle, setTooltipTitle] = useState('');
  const [tooltipText, setTooltipText] = useState('');
  const [descriptionTitle, setDescriptionTitle] = useState('');
  const [descriptionText, setDescriptionText] = useState('');
  const [descriptionTitleFontSize, setDescriptionTitleFontSize] = useState('');
  const [descriptionTextFontSize, setDescriptionTextFontSize] = useState('');
  const [descriptionTitleFontFamily, setDescriptionTitleFontFamily] =
    useState('');
  const [descriptionTextFontFamily, setDescriptionTextFontFamily] =
    useState('');
  const [descriptionTitleColor, setDescriptionTitleColor] = useState('');
  const [descriptionTextColor, setDescriptionTextColor] = useState('');
  const [descriptionBackgroundColor, setDescriptionBackgroundColor] =
    useState('');
  const [mediaUrl, setMediaUrl] = useState('');
  const [mediaAutoplay, setMediaAutoplay] = useState(false);
  const [mediaLoop, setMediaLoop] = useState(false);
  const [mediaMuted, setMediaMuted] = useState(false);
  const [carouselPrevIconUrl, setCarouselPrevIconUrl] = useState('');
  const [carouselNextIconUrl, setCarouselNextIconUrl] = useState('');
  const [galleryCards, setGalleryCards] = useState<GalleryCard[]>([]);
  const [carouselSlides, setCarouselSlides] = useState<CarouselSlide[]>([]);

  const applyElementToForm = useCallback((item: ConstructorElement) => {
    setLabel(String(item.label || ''));
    setXPercent(String(item.xPercent ?? 0));
    setYPercent(String(item.yPercent ?? 0));
    setWidth(extractNumericValue(item.width));
    setHeight(extractNumericValue(item.height));
    setMinWidth(extractNumericValue(item.minWidth));
    setMaxWidth(extractNumericValue(item.maxWidth));
    setMinHeight(extractNumericValue(item.minHeight));
    setMaxHeight(extractNumericValue(item.maxHeight));
    setMargin(String(item.margin || ''));
    setPadding(String(item.padding || ''));
    setGap(String(item.gap || ''));
    setFontSize(String(item.fontSize || ''));
    setLineHeight(String(item.lineHeight || ''));
    setFontWeight(String(item.fontWeight || ''));
    setBorder(extractNumericValue(item.border));
    setBorderRadius(extractNumericValue(item.borderRadius));
    setOpacity(item.opacity === '0' ? '0' : String(item.opacity || ''));
    setBoxShadow(String(item.boxShadow || ''));
    setDisplay(String(item.display || ''));
    setPosition(String(item.position || ''));
    setJustifyContent(String(item.justifyContent || ''));
    setAlignItems(String(item.alignItems || ''));
    setTextAlign(String(item.textAlign || ''));
    setZIndex(String(item.zIndex || ''));
    setAppearDelaySec(String(item.appearDelaySec ?? 0));
    setAppearDurationSec(
      item.appearDurationSec === null || item.appearDurationSec === undefined
        ? ''
        : String(item.appearDurationSec),
    );
    setIconUrl(String(item.iconUrl || ''));
    setNavLabel(String(item.navLabel || ''));
    setNavType(item.navType === 'back' ? 'back' : 'forward');
    setNavDisabled(Boolean(item.navDisabled));
    setTargetPageId(String(item.targetPageId || ''));
    setTransitionVideoUrl(String(item.transitionVideoUrl || ''));
    setTransitionReverseMode(
      item.transitionReverseMode === 'separate_video'
        ? 'separate_video'
        : 'auto_reverse',
    );
    setReverseVideoUrl(String(item.reverseVideoUrl || ''));
    setTransitionDurationSec(String(item.transitionDurationSec ?? 0.7));
    setTooltipTitle(String(item.tooltipTitle || ''));
    setTooltipText(String(item.tooltipText || ''));
    setDescriptionTitle(String(item.descriptionTitle || ''));
    setDescriptionText(String(item.descriptionText || ''));
    setDescriptionTitleFontSize(String(item.descriptionTitleFontSize || ''));
    setDescriptionTextFontSize(String(item.descriptionTextFontSize || ''));
    setDescriptionTitleFontFamily(
      String(item.descriptionTitleFontFamily || ''),
    );
    setDescriptionTextFontFamily(String(item.descriptionTextFontFamily || ''));
    setDescriptionTitleColor(String(item.descriptionTitleColor || ''));
    setDescriptionTextColor(String(item.descriptionTextColor || ''));
    setDescriptionBackgroundColor(
      String(item.descriptionBackgroundColor || ''),
    );
    setMediaUrl(String(item.mediaUrl || ''));
    setMediaAutoplay(Boolean(item.mediaAutoplay));
    setMediaLoop(Boolean(item.mediaLoop));
    setMediaMuted(Boolean(item.mediaMuted));
    setCarouselPrevIconUrl(String(item.carouselPrevIconUrl || ''));
    setCarouselNextIconUrl(String(item.carouselNextIconUrl || ''));
    setGalleryCards(
      Array.isArray(item.galleryCards)
        ? item.galleryCards.map((card, index) => ({
            id: String(card?.id || createLocalId()),
            imageUrl: String(card?.imageUrl || ''),
            title: String(card?.title || `Card ${index + 1}`),
            description: String(card?.description || ''),
          }))
        : [],
    );
    setCarouselSlides(
      Array.isArray(item.carouselSlides)
        ? item.carouselSlides.map((slide, index) => ({
            id: String(slide?.id || createLocalId()),
            imageUrl: String(slide?.imageUrl || ''),
            caption: String(slide?.caption || `Slide ${index + 1}`),
          }))
        : [],
    );
  }, []);

  const loadData = useCallback(async () => {
    if (!pageId || !elementId) return;

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

    try {
      const pageResponse = await axios.get(`/tour_pages/${pageId}`);
      const loadedPage = pageResponse?.data as TourPage;

      const schema = parseJsonObject<ConstructorSchema>(
        loadedPage?.ui_schema_json,
        {},
      );
      const elements = Array.isArray(schema.elements) ? schema.elements : [];
      const selectedElement = elements.find(
        (item) => String(item?.id || '') === elementId,
      );

      if (!selectedElement) {
        throw new Error('Element not found on this page.');
      }

      setCurrentPage(loadedPage);
      setElement(selectedElement);
      applyElementToForm(selectedElement);

      if (projectId) {
        const pagesResponse = await axios.get(
          `/tour_pages?limit=500&page=0&sort=asc&field=sort_order&project=${encodeURIComponent(projectId)}`,
        );
        const rows = Array.isArray(pagesResponse?.data?.rows)
          ? pagesResponse.data.rows
          : [];
        setProjectPages(rows);
      }
    } catch (error: any) {
      const message =
        error?.response?.data?.message ||
        error?.message ||
        'Failed to load element settings.';
      logger.error(
        'Failed to load dedicated element edit page:',
        error instanceof Error ? error : { error },
      );
      setErrorMessage(message);
      setCurrentPage(null);
      setElement(null);
      setProjectPages([]);
    } finally {
      setIsLoading(false);
    }
  }, [applyElementToForm, elementId, pageId, projectId]);

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

  const isNavigationType =
    element?.type === 'navigation_next' || element?.type === 'navigation_prev';
  const isTooltipType = element?.type === 'tooltip';
  const isDescriptionType = element?.type === 'description';
  const isGalleryType = element?.type === 'gallery';
  const isCarouselType = element?.type === 'carousel';
  const isMediaType =
    element?.type === 'video_player' || element?.type === 'audio_player';

  const updateGalleryCard = (
    cardId: string,
    field: keyof GalleryCard,
    value: string,
  ) => {
    setGalleryCards((previous) =>
      previous.map((card) =>
        card.id === cardId ? { ...card, [field]: value } : card,
      ),
    );
  };

  const addGalleryCard = () => {
    setGalleryCards((previous) => [
      ...previous,
      {
        id: createLocalId(),
        imageUrl: '',
        title: `Card ${previous.length + 1}`,
        description: '',
      },
    ]);
  };

  const removeGalleryCard = (cardId: string) => {
    setGalleryCards((previous) =>
      previous.filter((card) => card.id !== cardId),
    );
  };

  const updateCarouselSlide = (
    slideId: string,
    field: keyof CarouselSlide,
    value: string,
  ) => {
    setCarouselSlides((previous) =>
      previous.map((slide) =>
        slide.id === slideId ? { ...slide, [field]: value } : slide,
      ),
    );
  };

  const addCarouselSlide = () => {
    setCarouselSlides((previous) => [
      ...previous,
      {
        id: createLocalId(),
        imageUrl: '',
        caption: `Slide ${previous.length + 1}`,
      },
    ]);
  };

  const removeCarouselSlide = (slideId: string) => {
    setCarouselSlides((previous) =>
      previous.filter((slide) => slide.id !== slideId),
    );
  };

  const saveElement = async () => {
    if (!currentPage || !element || !hasUpdatePermission) return;

    setIsSaving(true);
    setErrorMessage('');
    setSuccessMessage('');

    try {
      const borderWidthValue = toUnitValue(border, 'px');
      const nextElement: ConstructorElement = {
        ...element,
        label: label.trim(),
        xPercent: clampPercent(xPercent),
        yPercent: clampPercent(yPercent),
        border: borderWidthValue
          ? `${borderWidthValue} solid currentColor`
          : 'none',
        borderRadius: toUnitValue(borderRadius, 'px') || '0px',
        appearDelaySec:
          Number(appearDelaySec) >= 0 ? Number(appearDelaySec) : 0,
        appearDurationSec: parseNullableNumber(appearDurationSec),
      };

      const widthValue = toUnitValue(width, 'vw');
      const heightValue = toUnitValue(height, 'vh');
      const minWidthValue = toUnitValue(minWidth, 'vw');
      const maxWidthValue = toUnitValue(maxWidth, 'vw');
      const minHeightValue = toUnitValue(minHeight, 'vh');
      const maxHeightValue = toUnitValue(maxHeight, 'vh');

      if (widthValue) nextElement.width = widthValue;
      else delete nextElement.width;
      if (heightValue) nextElement.height = heightValue;
      else delete nextElement.height;
      if (minWidthValue) nextElement.minWidth = minWidthValue;
      else delete nextElement.minWidth;
      if (maxWidthValue) nextElement.maxWidth = maxWidthValue;
      else delete nextElement.maxWidth;
      if (minHeightValue) nextElement.minHeight = minHeightValue;
      else delete nextElement.minHeight;
      if (maxHeightValue) nextElement.maxHeight = maxHeightValue;
      else delete nextElement.maxHeight;

      const marginValue = toOptionalTrimmed(margin);
      const paddingValue = toOptionalTrimmed(padding);
      const gapValue = toOptionalTrimmed(gap);
      const fontSizeValue = toOptionalTrimmed(fontSize);
      const lineHeightValue = toOptionalTrimmed(lineHeight);
      const fontWeightValue = toOptionalTrimmed(fontWeight);
      const opacityValue = toOptionalTrimmed(opacity);
      const boxShadowValue = toOptionalTrimmed(boxShadow);
      const displayValue = toOptionalTrimmed(display);
      const positionValue = toOptionalTrimmed(position);
      const justifyContentValue = toOptionalTrimmed(justifyContent);
      const alignItemsValue = toOptionalTrimmed(alignItems);
      const textAlignValue = toOptionalTrimmed(textAlign);
      const zIndexValue = toOptionalTrimmed(zIndex);

      if (marginValue) nextElement.margin = marginValue;
      else delete nextElement.margin;
      if (paddingValue) nextElement.padding = paddingValue;
      else delete nextElement.padding;
      if (gapValue) nextElement.gap = gapValue;
      else delete nextElement.gap;
      if (fontSizeValue) nextElement.fontSize = fontSizeValue;
      else delete nextElement.fontSize;
      if (lineHeightValue) nextElement.lineHeight = lineHeightValue;
      else delete nextElement.lineHeight;
      if (fontWeightValue) nextElement.fontWeight = fontWeightValue;
      else delete nextElement.fontWeight;
      if (opacityValue) nextElement.opacity = opacityValue;
      else delete nextElement.opacity;
      if (boxShadowValue) nextElement.boxShadow = boxShadowValue;
      else delete nextElement.boxShadow;
      if (displayValue) nextElement.display = displayValue;
      else delete nextElement.display;
      if (positionValue) nextElement.position = positionValue;
      else delete nextElement.position;
      if (justifyContentValue) nextElement.justifyContent = justifyContentValue;
      else delete nextElement.justifyContent;
      if (alignItemsValue) nextElement.alignItems = alignItemsValue;
      else delete nextElement.alignItems;
      if (textAlignValue) nextElement.textAlign = textAlignValue;
      else delete nextElement.textAlign;
      if (zIndexValue) nextElement.zIndex = zIndexValue;
      else delete nextElement.zIndex;

      if (isNavigationType) {
        nextElement.iconUrl = iconUrl.trim();
        nextElement.navLabel = navLabel.trim();
        nextElement.navType = navType;
        nextElement.navDisabled = navDisabled;
        nextElement.targetPageId = targetPageId.trim();
        nextElement.transitionVideoUrl = transitionVideoUrl.trim();
        nextElement.transitionReverseMode = transitionReverseMode;
        nextElement.reverseVideoUrl = reverseVideoUrl.trim();
        nextElement.transitionDurationSec =
          Number(transitionDurationSec) > 0
            ? Number(transitionDurationSec)
            : 0.7;
      }

      if (isTooltipType) {
        nextElement.iconUrl = iconUrl.trim();
        nextElement.tooltipTitle = tooltipTitle.trim();
        nextElement.tooltipText = tooltipText;
      }

      if (isDescriptionType) {
        nextElement.iconUrl = iconUrl.trim();
        nextElement.descriptionTitle = descriptionTitle.trim();
        nextElement.descriptionText = descriptionText;
        nextElement.descriptionTitleFontSize =
          descriptionTitleFontSize.trim() || '48px';
        nextElement.descriptionTextFontSize =
          descriptionTextFontSize.trim() || '36px';
        nextElement.descriptionTitleFontFamily =
          descriptionTitleFontFamily.trim() || 'inherit';
        nextElement.descriptionTextFontFamily =
          descriptionTextFontFamily.trim() || 'inherit';
        nextElement.descriptionTitleColor =
          descriptionTitleColor.trim() || '#000000';
        nextElement.descriptionTextColor =
          descriptionTextColor.trim() || '#4B5563';
        nextElement.descriptionBackgroundColor =
          descriptionBackgroundColor.trim() || 'transparent';
      }

      if (isGalleryType) {
        nextElement.galleryCards = galleryCards.map((card, index) => ({
          id: String(card.id || createLocalId()),
          imageUrl: card.imageUrl.trim(),
          title: card.title.trim() || `Card ${index + 1}`,
          description: card.description,
        }));
      }

      if (isCarouselType) {
        nextElement.carouselSlides = carouselSlides.map((slide, index) => ({
          id: String(slide.id || createLocalId()),
          imageUrl: slide.imageUrl.trim(),
          caption: slide.caption.trim() || `Slide ${index + 1}`,
        }));
        nextElement.carouselPrevIconUrl = carouselPrevIconUrl.trim();
        nextElement.carouselNextIconUrl = carouselNextIconUrl.trim();
      }

      if (isMediaType) {
        nextElement.mediaUrl = mediaUrl.trim();
        nextElement.mediaAutoplay = mediaAutoplay;
        nextElement.mediaLoop = mediaLoop;
        nextElement.mediaMuted = mediaMuted;
      }

      const existingSchema = parseJsonObject<ConstructorSchema>(
        currentPage.ui_schema_json,
        {},
      );
      const existingElements = Array.isArray(existingSchema.elements)
        ? existingSchema.elements
        : [];
      const updatedElements = existingElements.map((item) =>
        String(item.id) === String(element.id) ? nextElement : item,
      );

      await axios.put(`/tour_pages/${currentPage.id}`, {
        id: currentPage.id,
        data: {
          environment: currentPage.environment,
          source_key: currentPage.source_key,
          name: currentPage.name,
          slug: currentPage.slug,
          sort_order: currentPage.sort_order,
          requires_auth: currentPage.requires_auth,
          ui_schema_json: {
            ...existingSchema,
            elements: updatedElements,
          },
          background_image_url: currentPage.background_image_url,
          background_video_url: currentPage.background_video_url,
          background_audio_url: currentPage.background_audio_url,
          background_loop: currentPage.background_loop,
        },
      });

      setElement(nextElement);
      setCurrentPage((previous) =>
        previous
          ? {
              ...previous,
              ui_schema_json: {
                ...existingSchema,
                elements: updatedElements,
              },
            }
          : previous,
      );
      setSuccessMessage('Element settings saved.');
    } catch (error: any) {
      const message =
        error?.response?.data?.message ||
        error?.message ||
        'Failed to save element settings.';
      logger.error(
        'Failed to save dedicated element settings:',
        error instanceof Error ? error : { error },
      );
      setErrorMessage(message);
    } finally {
      setIsSaving(false);
    }
  };

  const backHref = projectId
    ? `/page_elements/page_elements-list?projectId=${encodeURIComponent(projectId)}`
    : '/page_elements/page_elements-list';

  return (
    <>
      <Head>
        <title>{getPageTitle('Edit Element')}</title>
      </Head>
      <SectionMain>
        <SectionTitleLineWithButton
          icon={mdiPencil}
          title='Edit Element Settings'
          main
        >
          {''}
        </SectionTitleLineWithButton>

        <CardBox className='mb-4'>
          <div className='flex flex-wrap items-center gap-2'>
            <Link href={backHref}>
              <BaseButton
                icon={mdiArrowLeft}
                label='Back to Elements'
                color='lightDark'
              />
            </Link>
            <BaseButton
              color='success'
              icon={mdiContentSave}
              label={isSaving ? 'Saving...' : 'Save'}
              onClick={saveElement}
              disabled={
                isSaving || isLoading || !element || !hasUpdatePermission
              }
            />
          </div>
        </CardBox>

        {errorMessage ? (
          <CardBox className='mb-4 text-sm text-red-600'>
            {errorMessage}
          </CardBox>
        ) : null}
        {successMessage ? (
          <CardBox className='mb-4 text-sm text-green-600'>
            {successMessage}
          </CardBox>
        ) : null}

        {isLoading ? (
          <CardBox>
            <p className='text-sm text-gray-500'>Loading element settings...</p>
          </CardBox>
        ) : !element ? (
          <CardBox>
            <p className='text-sm text-gray-500'>Element was not found.</p>
          </CardBox>
        ) : (
          <>
            <CardBox className='mb-4'>
              <p className='text-xs text-gray-500'>Element ID: {element.id}</p>
              <p className='text-xs text-gray-500'>
                Page: {currentPage?.name || currentPage?.id}
              </p>
              <p className='mt-1 text-sm font-semibold'>Type: {element.type}</p>
            </CardBox>

            <CardBox className='mb-4'>
              <h3 className='mb-3 text-sm font-semibold'>General</h3>
              <div className='grid gap-4 md:grid-cols-2'>
                <FormField label='Label'>
                  <input
                    value={label}
                    onChange={(event) => setLabel(event.target.value)}
                    disabled={!hasUpdatePermission}
                  />
                </FormField>
                <FormField label='X percent'>
                  <input
                    value={xPercent}
                    onChange={(event) => setXPercent(event.target.value)}
                    disabled={!hasUpdatePermission}
                  />
                </FormField>
                <FormField label='Y percent'>
                  <input
                    value={yPercent}
                    onChange={(event) => setYPercent(event.target.value)}
                    disabled={!hasUpdatePermission}
                  />
                </FormField>
                <FormField label='Appear delay (sec)'>
                  <input
                    value={appearDelaySec}
                    onChange={(event) => setAppearDelaySec(event.target.value)}
                    disabled={!hasUpdatePermission}
                  />
                </FormField>
                <FormField label='Appear duration (sec)'>
                  <input
                    value={appearDurationSec}
                    onChange={(event) =>
                      setAppearDurationSec(event.target.value)
                    }
                    placeholder='Leave empty for none'
                    disabled={!hasUpdatePermission}
                  />
                </FormField>
              </div>
            </CardBox>

            <CardBox className='mb-4'>
              <h3 className='mb-3 text-sm font-semibold'>View & stylization</h3>
              <p className='mb-3 text-xs text-gray-500'>
                Fill numbers only: width is saved as vw, height as vh, border
                and radius as px.
              </p>
              <div className='grid gap-4 md:grid-cols-2'>
                <FormField label='Width (vw)'>
                  <input
                    type='number'
                    step='0.1'
                    min='0'
                    value={width}
                    onChange={(event) => setWidth(event.target.value)}
                    disabled={!hasUpdatePermission}
                    placeholder='e.g. 24'
                  />
                </FormField>
                <FormField label='Height (vh)'>
                  <input
                    type='number'
                    step='0.1'
                    min='0'
                    value={height}
                    onChange={(event) => setHeight(event.target.value)}
                    disabled={!hasUpdatePermission}
                    placeholder='e.g. 8'
                  />
                </FormField>
                <FormField label='Min width (vw)'>
                  <input
                    type='number'
                    step='0.1'
                    min='0'
                    value={minWidth}
                    onChange={(event) => setMinWidth(event.target.value)}
                    disabled={!hasUpdatePermission}
                  />
                </FormField>
                <FormField label='Max width (vw)'>
                  <input
                    type='number'
                    step='0.1'
                    min='0'
                    value={maxWidth}
                    onChange={(event) => setMaxWidth(event.target.value)}
                    disabled={!hasUpdatePermission}
                  />
                </FormField>
                <FormField label='Min height (vh)'>
                  <input
                    type='number'
                    step='0.1'
                    min='0'
                    value={minHeight}
                    onChange={(event) => setMinHeight(event.target.value)}
                    disabled={!hasUpdatePermission}
                  />
                </FormField>
                <FormField label='Max height (vh)'>
                  <input
                    type='number'
                    step='0.1'
                    min='0'
                    value={maxHeight}
                    onChange={(event) => setMaxHeight(event.target.value)}
                    disabled={!hasUpdatePermission}
                  />
                </FormField>
                <FormField label='Margin'>
                  <input
                    value={margin}
                    onChange={(event) => setMargin(event.target.value)}
                    disabled={!hasUpdatePermission}
                    placeholder='e.g. 0 auto / 0.5rem'
                  />
                </FormField>
                <FormField label='Padding'>
                  <input
                    value={padding}
                    onChange={(event) => setPadding(event.target.value)}
                    disabled={!hasUpdatePermission}
                    placeholder='e.g. 0.5rem 0.75rem'
                  />
                </FormField>
                <FormField label='Gap'>
                  <input
                    value={gap}
                    onChange={(event) => setGap(event.target.value)}
                    disabled={!hasUpdatePermission}
                  />
                </FormField>
                <FormField label='Font size'>
                  <input
                    value={fontSize}
                    onChange={(event) => setFontSize(event.target.value)}
                    disabled={!hasUpdatePermission}
                    placeholder='e.g. 0.875rem / clamp(...)'
                  />
                </FormField>
                <FormField label='Line height'>
                  <input
                    value={lineHeight}
                    onChange={(event) => setLineHeight(event.target.value)}
                    disabled={!hasUpdatePermission}
                  />
                </FormField>
                <FormField label='Font weight'>
                  <input
                    value={fontWeight}
                    onChange={(event) => setFontWeight(event.target.value)}
                    disabled={!hasUpdatePermission}
                    placeholder='e.g. 500 / bold'
                  />
                </FormField>
                <FormField label='Border width (px)'>
                  <input
                    type='number'
                    step='1'
                    min='0'
                    value={border}
                    onChange={(event) => setBorder(event.target.value)}
                    disabled={!hasUpdatePermission}
                    placeholder='empty = none'
                  />
                </FormField>
                <FormField label='Border radius (px)'>
                  <input
                    type='number'
                    step='1'
                    min='0'
                    value={borderRadius}
                    onChange={(event) => setBorderRadius(event.target.value)}
                    disabled={!hasUpdatePermission}
                    placeholder='empty = 0'
                  />
                </FormField>
                <FormField label='Opacity'>
                  <input
                    value={opacity}
                    onChange={(event) => setOpacity(event.target.value)}
                    disabled={!hasUpdatePermission}
                    placeholder='0..1'
                  />
                </FormField>
                <FormField label='Shadow'>
                  <input
                    value={boxShadow}
                    onChange={(event) => setBoxShadow(event.target.value)}
                    disabled={!hasUpdatePermission}
                    placeholder='e.g. 0 4px 12px rgba(...)'
                  />
                </FormField>
                <FormField label='Display'>
                  <select
                    value={display}
                    onChange={(event) => setDisplay(event.target.value)}
                    disabled={!hasUpdatePermission}
                  >
                    <option value=''>Not set</option>
                    <option value='block'>block</option>
                    <option value='inline-block'>inline-block</option>
                    <option value='flex'>flex</option>
                    <option value='inline-flex'>inline-flex</option>
                    <option value='grid'>grid</option>
                    <option value='none'>none</option>
                  </select>
                </FormField>
                <FormField label='Position'>
                  <select
                    value={position}
                    onChange={(event) => setPosition(event.target.value)}
                    disabled={!hasUpdatePermission}
                  >
                    <option value=''>Not set</option>
                    <option value='static'>static</option>
                    <option value='relative'>relative</option>
                    <option value='absolute'>absolute</option>
                    <option value='fixed'>fixed</option>
                    <option value='sticky'>sticky</option>
                  </select>
                </FormField>
                <FormField label='Justify content'>
                  <select
                    value={justifyContent}
                    onChange={(event) => setJustifyContent(event.target.value)}
                    disabled={!hasUpdatePermission}
                  >
                    <option value=''>Not set</option>
                    <option value='flex-start'>flex-start</option>
                    <option value='center'>center</option>
                    <option value='flex-end'>flex-end</option>
                    <option value='space-between'>space-between</option>
                    <option value='space-around'>space-around</option>
                    <option value='space-evenly'>space-evenly</option>
                  </select>
                </FormField>
                <FormField label='Align items'>
                  <select
                    value={alignItems}
                    onChange={(event) => setAlignItems(event.target.value)}
                    disabled={!hasUpdatePermission}
                  >
                    <option value=''>Not set</option>
                    <option value='stretch'>stretch</option>
                    <option value='flex-start'>flex-start</option>
                    <option value='center'>center</option>
                    <option value='flex-end'>flex-end</option>
                    <option value='baseline'>baseline</option>
                  </select>
                </FormField>
                <FormField label='Text align'>
                  <select
                    value={textAlign}
                    onChange={(event) => setTextAlign(event.target.value)}
                    disabled={!hasUpdatePermission}
                  >
                    <option value=''>Not set</option>
                    <option value='left'>left</option>
                    <option value='center'>center</option>
                    <option value='right'>right</option>
                    <option value='justify'>justify</option>
                  </select>
                </FormField>
                <FormField label='z-index'>
                  <input
                    value={zIndex}
                    onChange={(event) => setZIndex(event.target.value)}
                    disabled={!hasUpdatePermission}
                    placeholder='e.g. 1 / 10'
                  />
                </FormField>
              </div>
            </CardBox>

            {isNavigationType ? (
              <CardBox className='mb-4'>
                <h3 className='mb-3 text-sm font-semibold'>Navigation</h3>
                <div className='grid gap-4 md:grid-cols-2'>
                  <FormField label='Icon URL'>
                    <input
                      value={iconUrl}
                      onChange={(event) => setIconUrl(event.target.value)}
                      disabled={!hasUpdatePermission}
                    />
                  </FormField>
                  <FormField label='Navigation label'>
                    <input
                      value={navLabel}
                      onChange={(event) => setNavLabel(event.target.value)}
                      disabled={!hasUpdatePermission}
                    />
                  </FormField>
                  <FormField label='Navigation type'>
                    <select
                      value={navType}
                      onChange={(event) =>
                        setNavType(
                          event.target.value === 'back' ? 'back' : 'forward',
                        )
                      }
                      disabled={!hasUpdatePermission}
                    >
                      <option value='forward'>Forward</option>
                      <option value='back'>Back</option>
                    </select>
                  </FormField>
                  <FormField label='Disabled'>
                    <label className='flex items-center gap-2 text-sm pt-2'>
                      <input
                        type='checkbox'
                        checked={navDisabled}
                        onChange={(event) =>
                          setNavDisabled(event.target.checked)
                        }
                        disabled={!hasUpdatePermission}
                      />
                      Button is disabled (not clickable)
                    </label>
                  </FormField>
                  <FormField label='Target page'>
                    <select
                      value={targetPageId}
                      onChange={(event) => setTargetPageId(event.target.value)}
                      disabled={!hasUpdatePermission}
                    >
                      <option value=''>None</option>
                      {projectPages.map((page) => (
                        <option key={page.id} value={page.id}>
                          {page.name || page.id}
                        </option>
                      ))}
                    </select>
                  </FormField>
                  <FormField label='Transition video URL'>
                    <input
                      value={transitionVideoUrl}
                      onChange={(event) =>
                        setTransitionVideoUrl(event.target.value)
                      }
                      disabled={!hasUpdatePermission}
                    />
                  </FormField>
                  <FormField label='Reverse mode'>
                    <select
                      value={transitionReverseMode}
                      onChange={(event) =>
                        setTransitionReverseMode(
                          event.target.value === 'separate_video'
                            ? 'separate_video'
                            : 'auto_reverse',
                        )
                      }
                      disabled={!hasUpdatePermission}
                    >
                      <option value='auto_reverse'>Auto reverse</option>
                      <option value='separate_video'>
                        Separate reverse video
                      </option>
                    </select>
                  </FormField>
                  {transitionReverseMode === 'separate_video' ? (
                    <FormField label='Reverse video URL'>
                      <input
                        value={reverseVideoUrl}
                        onChange={(event) =>
                          setReverseVideoUrl(event.target.value)
                        }
                        disabled={!hasUpdatePermission}
                      />
                    </FormField>
                  ) : null}
                  <FormField label='Transition duration (sec)'>
                    <input
                      value={transitionDurationSec}
                      onChange={(event) =>
                        setTransitionDurationSec(event.target.value)
                      }
                      disabled={!hasUpdatePermission}
                    />
                  </FormField>
                </div>
              </CardBox>
            ) : null}

            {isTooltipType ? (
              <CardBox className='mb-4'>
                <h3 className='mb-3 text-sm font-semibold'>Tooltip</h3>
                <div className='grid gap-4 md:grid-cols-2'>
                  <FormField label='Icon URL'>
                    <input
                      value={iconUrl}
                      onChange={(event) => setIconUrl(event.target.value)}
                      disabled={!hasUpdatePermission}
                    />
                  </FormField>
                  <FormField label='Tooltip title'>
                    <input
                      value={tooltipTitle}
                      onChange={(event) => setTooltipTitle(event.target.value)}
                      disabled={!hasUpdatePermission}
                    />
                  </FormField>
                  <div className='md:col-span-2'>
                    <FormField label='Tooltip text' hasTextareaHeight>
                      <textarea
                        className='h-24 w-full rounded border border-gray-300 px-2 py-2 dark:border-dark-700 dark:bg-dark-800'
                        value={tooltipText}
                        onChange={(event) => setTooltipText(event.target.value)}
                        disabled={!hasUpdatePermission}
                      />
                    </FormField>
                  </div>
                </div>
              </CardBox>
            ) : null}

            {isDescriptionType ? (
              <CardBox className='mb-4'>
                <h3 className='mb-3 text-sm font-semibold'>Description</h3>
                <div className='grid gap-4 md:grid-cols-2'>
                  <FormField label='Icon URL'>
                    <input
                      value={iconUrl}
                      onChange={(event) => setIconUrl(event.target.value)}
                      disabled={!hasUpdatePermission}
                    />
                  </FormField>
                  <FormField label='Description title'>
                    <input
                      value={descriptionTitle}
                      onChange={(event) =>
                        setDescriptionTitle(event.target.value)
                      }
                      disabled={!hasUpdatePermission}
                    />
                  </FormField>
                  <div className='md:col-span-2'>
                    <FormField label='Description text' hasTextareaHeight>
                      <textarea
                        className='h-24 w-full rounded border border-gray-300 px-2 py-2 dark:border-dark-700 dark:bg-dark-800'
                        value={descriptionText}
                        onChange={(event) =>
                          setDescriptionText(event.target.value)
                        }
                        disabled={!hasUpdatePermission}
                      />
                    </FormField>
                  </div>
                  <FormField label='Title font size'>
                    <input
                      value={descriptionTitleFontSize}
                      onChange={(event) =>
                        setDescriptionTitleFontSize(event.target.value)
                      }
                      disabled={!hasUpdatePermission}
                      placeholder='e.g. 48px'
                    />
                  </FormField>
                  <FormField label='Text font size'>
                    <input
                      value={descriptionTextFontSize}
                      onChange={(event) =>
                        setDescriptionTextFontSize(event.target.value)
                      }
                      disabled={!hasUpdatePermission}
                      placeholder='e.g. 36px'
                    />
                  </FormField>
                  <FormField label='Title font family'>
                    <input
                      value={descriptionTitleFontFamily}
                      onChange={(event) =>
                        setDescriptionTitleFontFamily(event.target.value)
                      }
                      disabled={!hasUpdatePermission}
                      placeholder='e.g. Arial, sans-serif'
                    />
                  </FormField>
                  <FormField label='Text font family'>
                    <input
                      value={descriptionTextFontFamily}
                      onChange={(event) =>
                        setDescriptionTextFontFamily(event.target.value)
                      }
                      disabled={!hasUpdatePermission}
                      placeholder='e.g. Arial, sans-serif'
                    />
                  </FormField>
                  <FormField label='Title color'>
                    <input
                      type='color'
                      value={descriptionTitleColor || '#000000'}
                      onChange={(event) =>
                        setDescriptionTitleColor(event.target.value)
                      }
                      disabled={!hasUpdatePermission}
                      className='h-10 w-full'
                    />
                  </FormField>
                  <FormField label='Text color'>
                    <input
                      type='color'
                      value={descriptionTextColor || '#4B5563'}
                      onChange={(event) =>
                        setDescriptionTextColor(event.target.value)
                      }
                      disabled={!hasUpdatePermission}
                      className='h-10 w-full'
                    />
                  </FormField>
                  <FormField label='Background color'>
                    <input
                      value={descriptionBackgroundColor}
                      onChange={(event) =>
                        setDescriptionBackgroundColor(event.target.value)
                      }
                      disabled={!hasUpdatePermission}
                      placeholder='e.g. transparent, #ffffff'
                    />
                  </FormField>
                </div>
              </CardBox>
            ) : null}

            {isMediaType ? (
              <CardBox className='mb-4'>
                <h3 className='mb-3 text-sm font-semibold'>Media</h3>
                <div className='grid gap-4 md:grid-cols-2'>
                  <div className='md:col-span-2'>
                    <FormField label='Media URL'>
                      <input
                        value={mediaUrl}
                        onChange={(event) => setMediaUrl(event.target.value)}
                        disabled={!hasUpdatePermission}
                      />
                    </FormField>
                  </div>
                  <FormField label='Playback options'>
                    <div className='flex flex-wrap gap-4 pt-2'>
                      <label className='flex items-center gap-2 text-sm'>
                        <input
                          type='checkbox'
                          checked={mediaAutoplay}
                          onChange={(event) =>
                            setMediaAutoplay(event.target.checked)
                          }
                          disabled={!hasUpdatePermission}
                        />
                        Autoplay
                      </label>
                      <label className='flex items-center gap-2 text-sm'>
                        <input
                          type='checkbox'
                          checked={mediaLoop}
                          onChange={(event) =>
                            setMediaLoop(event.target.checked)
                          }
                          disabled={!hasUpdatePermission}
                        />
                        Loop
                      </label>
                      <label className='flex items-center gap-2 text-sm'>
                        <input
                          type='checkbox'
                          checked={mediaMuted}
                          onChange={(event) =>
                            setMediaMuted(event.target.checked)
                          }
                          disabled={!hasUpdatePermission}
                        />
                        Muted
                      </label>
                    </div>
                  </FormField>
                </div>
              </CardBox>
            ) : null}

            {isGalleryType ? (
              <CardBox className='mb-4'>
                <div className='mb-3 flex items-center justify-between'>
                  <h3 className='text-sm font-semibold'>Gallery cards</h3>
                  <BaseButton
                    color='info'
                    icon={mdiPlus}
                    small
                    label='Add card'
                    onClick={addGalleryCard}
                    disabled={!hasUpdatePermission}
                  />
                </div>

                <div className='space-y-4'>
                  {galleryCards.length === 0 ? (
                    <p className='text-sm text-gray-500'>No cards yet.</p>
                  ) : (
                    galleryCards.map((card, index) => (
                      <CardBox
                        key={card.id}
                        className='border border-gray-200 dark:border-dark-700'
                      >
                        <div className='mb-3 flex items-center justify-between'>
                          <h4 className='text-sm font-semibold'>
                            Card {index + 1}
                          </h4>
                          <BaseButton
                            color='danger'
                            icon={mdiTrashCan}
                            small
                            outline
                            onClick={() => removeGalleryCard(card.id)}
                            disabled={!hasUpdatePermission}
                          />
                        </div>
                        <div className='grid gap-3 md:grid-cols-2'>
                          <FormField label='Image URL'>
                            <input
                              value={card.imageUrl}
                              onChange={(event) =>
                                updateGalleryCard(
                                  card.id,
                                  'imageUrl',
                                  event.target.value,
                                )
                              }
                              disabled={!hasUpdatePermission}
                            />
                          </FormField>
                          <FormField label='Title'>
                            <input
                              value={card.title}
                              onChange={(event) =>
                                updateGalleryCard(
                                  card.id,
                                  'title',
                                  event.target.value,
                                )
                              }
                              disabled={!hasUpdatePermission}
                            />
                          </FormField>
                          <div className='md:col-span-2'>
                            <FormField label='Description' hasTextareaHeight>
                              <textarea
                                className='h-24 w-full rounded border border-gray-300 px-2 py-2 dark:border-dark-700 dark:bg-dark-800'
                                value={card.description}
                                onChange={(event) =>
                                  updateGalleryCard(
                                    card.id,
                                    'description',
                                    event.target.value,
                                  )
                                }
                                disabled={!hasUpdatePermission}
                              />
                            </FormField>
                          </div>
                        </div>
                      </CardBox>
                    ))
                  )}
                </div>
              </CardBox>
            ) : null}

            {isCarouselType ? (
              <CardBox className='mb-4'>
                <h3 className='mb-3 text-sm font-semibold'>
                  Carousel settings
                </h3>
                <div className='grid gap-4 md:grid-cols-2'>
                  <FormField label='Previous icon URL'>
                    <input
                      value={carouselPrevIconUrl}
                      onChange={(event) =>
                        setCarouselPrevIconUrl(event.target.value)
                      }
                      disabled={!hasUpdatePermission}
                    />
                  </FormField>
                  <FormField label='Next icon URL'>
                    <input
                      value={carouselNextIconUrl}
                      onChange={(event) =>
                        setCarouselNextIconUrl(event.target.value)
                      }
                      disabled={!hasUpdatePermission}
                    />
                  </FormField>
                </div>

                <div className='mb-3 mt-2 flex items-center justify-between'>
                  <h3 className='text-sm font-semibold'>Carousel slides</h3>
                  <BaseButton
                    color='info'
                    icon={mdiPlus}
                    small
                    label='Add slide'
                    onClick={addCarouselSlide}
                    disabled={!hasUpdatePermission}
                  />
                </div>

                <div className='space-y-4'>
                  {carouselSlides.length === 0 ? (
                    <p className='text-sm text-gray-500'>No slides yet.</p>
                  ) : (
                    carouselSlides.map((slide, index) => (
                      <CardBox
                        key={slide.id}
                        className='border border-gray-200 dark:border-dark-700'
                      >
                        <div className='mb-3 flex items-center justify-between'>
                          <h4 className='text-sm font-semibold'>
                            Slide {index + 1}
                          </h4>
                          <BaseButton
                            color='danger'
                            icon={mdiTrashCan}
                            small
                            outline
                            onClick={() => removeCarouselSlide(slide.id)}
                            disabled={!hasUpdatePermission}
                          />
                        </div>
                        <div className='grid gap-3 md:grid-cols-2'>
                          <FormField label='Image URL'>
                            <input
                              value={slide.imageUrl}
                              onChange={(event) =>
                                updateCarouselSlide(
                                  slide.id,
                                  'imageUrl',
                                  event.target.value,
                                )
                              }
                              disabled={!hasUpdatePermission}
                            />
                          </FormField>
                          <FormField label='Caption'>
                            <input
                              value={slide.caption}
                              onChange={(event) =>
                                updateCarouselSlide(
                                  slide.id,
                                  'caption',
                                  event.target.value,
                                )
                              }
                              disabled={!hasUpdatePermission}
                            />
                          </FormField>
                        </div>
                      </CardBox>
                    ))
                  )}
                </div>
              </CardBox>
            ) : null}
          </>
        )}
      </SectionMain>
    </>
  );
};

PageElementsProjectEditPage.getLayout = function getLayout(page: ReactElement) {
  return page;
};

export default PageElementsProjectEditPage;
