import { useAppDispatch, useAppSelector } from "@/app/hooks";
import { ResponsiveDialog } from "@/components/Dialog";
import EventFormFields from "@/components/Event/EventFormFields";
import { addDays } from "@/components/Event/utils/dateRules";
import {
  formatDateTimeInTimezone,
  formatLocalDateTime,
} from "@/components/Event/utils/dateTimeFormatters";
import { convertFormDateTimeToISO } from "@/components/Event/utils/dateTimeHelpers";
import { assertThunkSuccess } from "@/utils/assertThunkSuccess";
import {
  buildEventFormTempData,
  clearEventFormTempData,
  EventFormState,
  restoreEventFormDataFromTemp as restoreEventFormDataFromStorage,
  restoreFormDataFromTemp,
  saveEventFormDataToTemp,
  showErrorNotification,
} from "@/utils/eventFormTempStorage";
import { useSelectedCalendars } from "@/utils/storage/useSelectedCalendars";
import {
  browserDefaultTimeZone,
  getTimezoneOffset,
  resolveTimezone,
} from "@/utils/timezone";
import { TIMEZONES } from "@/utils/timezone-data";
import { addVideoConferenceToDescription } from "@/utils/videoConferenceUtils";
import { CalendarApi, DateSelectArg } from "@fullcalendar/core";
import { Box, Button } from "@linagora/twake-mui";
import AddIcon from "@mui/icons-material/Add";
import React, {
  startTransition,
  useCallback,
  useEffect,
  useMemo,
  useRef,
  useState,
} from "react";
import { useI18n } from "twake-i18n";
import { Calendar } from "../Calendars/CalendarTypes";
import { putEventAsync } from "../Calendars/services";
import { userAttendee } from "../User/models/attendee";
import { CalendarEvent, RepetitionObject } from "./EventsTypes";
import { buildDelegatedEventURL } from "./eventUtils";
import { useEventOrganizer } from "./useEventOrganizer";

function EventPopover({
  open,
  onClose,
  selectedRange,
  setSelectedRange,
  calendarRef,
  event,
}: {
  anchorEl: HTMLElement | null;
  open: boolean;
  onClose: (refresh?: boolean) => void;
  selectedRange: DateSelectArg | null;
  setSelectedRange: React.Dispatch<React.SetStateAction<DateSelectArg | null>>;
  calendarRef: React.RefObject<CalendarApi | null>;
  event?: CalendarEvent;
}) {
  const dispatch = useAppDispatch();
  const { t } = useI18n();
  const selectedCalendarIds = useSelectedCalendars();

  const userOrganizer = useAppSelector((state) => state.user.organiserData);
  const userId =
    useAppSelector((state) => state.user.userData?.openpaasId) ?? "";
  const calList = useAppSelector((state) => state.calendars.list);
  const userPersonalCalendars: Calendar[] = Object.values(calList || {}).filter(
    (cal) =>
      cal.id?.split("/")[0] === userId || (cal.delegated && cal.access?.write)
  );

  const timezoneList = useMemo(() => {
    const zones = Object.keys(TIMEZONES.zones).sort();
    const browserTz = resolveTimezone(browserDefaultTimeZone);

    return { zones, browserTz, getTimezoneOffset };
  }, []);

  const calendarTimezone = useAppSelector((state) => state.settings.timeZone);
  const resolvedCalendarTimezone = useMemo(() => {
    const tz = calendarTimezone || browserDefaultTimeZone;
    return resolveTimezone(tz);
  }, [calendarTimezone]);

  const [showMore, setShowMore] = useState(false);
  const [showDescription, setShowDescription] = useState(
    event?.description ? true : false
  );
  const [showRepeat, setShowRepeat] = useState(
    event?.repetition?.freq ? true : false
  );

  const [title, setTitle] = useState(event?.title ?? "");

  const [description, setDescription] = useState(event?.description ?? "");
  const [location, setLocation] = useState(event?.location ?? "");
  const [start, setStart] = useState(event?.start ? event.start : "");
  const [end, setEnd] = useState(event?.end ? event.end : "");
  const defaultCalendarId = useMemo(() => {
    const selectedAndWritable = Object.values(calList ?? {})
      .filter((cal) => selectedCalendarIds.includes(cal.id))
      .filter(
        (cal) =>
          (cal.delegated && cal.access?.write) ||
          userId === cal.id?.split("/")[0]
      );

    if (selectedAndWritable.length > 0) {
      return selectedAndWritable[0].id!;
    }

    const firstPersonal = Object.values(calList ?? {}).find(
      (cal) =>
        cal.id?.split("/")[0] === userId || (cal.delegated && cal.access?.write)
    );
    return firstPersonal?.id ?? "";
  }, [selectedCalendarIds, calList, userId]);

  const [calendarid, setCalendarid] = useState(
    event?.calId ?? defaultCalendarId
  );
  const [allday, setAllDay] = useState(event?.allday ?? false);
  const [repetition, setRepetition] = useState<RepetitionObject>(
    event?.repetition ?? ({} as RepetitionObject)
  );

  // Derive the effective organizer based on the selected calendar.
  // When a delegated calendar is selected, the organizer must be the
  // calendar owner, not the logged-in user.
  const { organizer } = useEventOrganizer({
    calendarid,
    calList,
    userOrganizer,
  });

  const [attendees, setAttendees] = useState<userAttendee[]>(
    event?.attendee
      ? event.attendee.filter((a) => a.cal_address !== organizer?.cal_address)
      : []
  );
  const [alarm, setAlarm] = useState(event?.alarm?.trigger ?? "");
  const [eventClass, setEventClass] = useState(event?.class ?? "PUBLIC");
  const [busy, setBusy] = useState(event?.transp ?? "OPAQUE");
  const [timezone, setTimezone] = useState(
    event?.timezone ? resolveTimezone(event.timezone) : resolvedCalendarTimezone
  );
  const [hasVideoConference, setHasVideoConference] = useState(
    event?.x_openpass_videoconference ? true : false
  );
  const [meetingLink, setMeetingLink] = useState<string | null>(
    event?.x_openpass_videoconference || null
  );
  const [isFormValid, setIsFormValid] = useState(false);
  const [showValidationErrors, setShowValidationErrors] = useState(false);
  const [hasEndDateChanged, setHasEndDateChanged] = useState(false);

  // Use ref to track if we've already initialized to avoid infinite loop
  const isInitializedRef = useRef(false);
  const userPersonalCalendarsRef = useRef(userPersonalCalendars);
  // Track when restoring from error to prevent other useEffects from overriding restored data
  const isRestoringFromErrorRef = useRef(false);
  // Track whether the user has explicitly picked a calendar so we don't override their choice
  const isCalendarIdUserSelectedRef = useRef(false);

  // Update ref when userPersonalCalendars changes
  useEffect(() => {
    userPersonalCalendarsRef.current = userPersonalCalendars;
  }, [userPersonalCalendars]);

  // Sync calendarid whenever defaultCalendarId resolves, unless the user already picked one
  useEffect(() => {
    if (!isCalendarIdUserSelectedRef.current && defaultCalendarId) {
      setCalendarid(defaultCalendarId);
    }
  }, [defaultCalendarId]);

  const resetAllStateToDefault = useCallback(() => {
    setShowMore(false);
    setShowDescription(false);
    setShowRepeat(false);
    setTitle("");
    setDescription("");
    setAttendees([]);
    setLocation("");
    setStart("");
    setEnd("");
    if (defaultCalendarId) {
      setCalendarid(defaultCalendarId);
    }
    setAllDay(false);
    setRepetition({} as RepetitionObject);
    setAlarm("");
    setEventClass("PUBLIC");
    setBusy("OPAQUE");
    setTimezone(resolvedCalendarTimezone);
    setHasVideoConference(false);
    setMeetingLink(null);
    setHasEndDateChanged(false);
  }, [resolvedCalendarTimezone, defaultCalendarId]);

  // Track if we should sync from selectedRange (only on initial selection, not on toggle)
  const shouldSyncFromRangeRef = useRef(true);
  const prevOpenRef = useRef(false);

  // Sync timezone when modal opens or calendarTimezone changes
  useEffect(() => {
    // Detect modal opening (transition from closed to open)
    const isOpening = open && !prevOpenRef.current;

    if (isOpening) {
      shouldSyncFromRangeRef.current = true;
      setShowValidationErrors(false);

      // Set timezone to calendar timezone for new events when opening
      const isNewEvent = !event || !event.uid;
      if (isNewEvent) {
        setTimezone(resolvedCalendarTimezone);
      }
    }

    // Update previous open state
    prevOpenRef.current = open;
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [open, event?.uid, resolvedCalendarTimezone]);

  // Separately sync timezone when calendarTimezone changes while modal is open for new events
  useEffect(() => {
    if (open && (!event || !event.uid)) {
      setTimezone(resolvedCalendarTimezone);
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [resolvedCalendarTimezone, open, event?.uid]);

  // Set start/end times when modal opens for new event creation
  useEffect(() => {
    // Skip if restoring from error - data already restored
    if (isRestoringFromErrorRef.current) {
      return;
    }
    // Only run when modal opens and not duplicating an event
    // Check if event has uid to determine if it's a valid event (not empty object)
    if (!shouldSyncFromRangeRef.current || !open || (event && event.uid)) {
      return;
    }

    if (selectedRange && selectedRange.start && selectedRange.end) {
      // Auto-check allday if selectedRange is all-day
      if (selectedRange.allDay) {
        setAllDay(true);
      }

      // selectedRange gives us the visual time displayed on calendar
      // Use selectedRange.startStr and endStr if available (from FullCalendar)
      if (selectedRange.startStr && selectedRange.endStr) {
        // Check if they are strings (from FullCalendar) or need conversion
        const startStr =
          typeof selectedRange.startStr === "string"
            ? selectedRange.startStr
            : formatLocalDateTime(selectedRange.start);
        const endStr =
          typeof selectedRange.endStr === "string"
            ? selectedRange.endStr
            : formatLocalDateTime(selectedRange.end);

        // Use the string values directly to preserve the displayed time
        const startValue = selectedRange.allDay
          ? startStr.split("T")[0]
          : startStr.slice(0, 16); // YYYY-MM-DDTHH:mm
        let endValue = selectedRange.allDay
          ? endStr.split("T")[0]
          : endStr.slice(0, 16);

        // For all-day slots: detect single click vs drag multiple days
        // FullCalendar uses exclusive end, so end date = actual end date + 1
        // For UI display, we need to adjust:
        // - Single click (end = start + 1): set end = start for UI
        // - Drag multiple days (end = actual end + 1): set end = end - 1 for UI
        if (selectedRange.allDay) {
          const startDateOnly = startValue.slice(0, 10);
          const endDateOnlyFromRange = endValue.slice(0, 10);

          // Calculate days difference
          const startDateObj = new Date(startDateOnly);
          const endDateObj = new Date(endDateOnlyFromRange);
          const daysDiff = Math.floor(
            (endDateObj.getTime() - startDateObj.getTime()) /
              (1000 * 60 * 60 * 24)
          );

          if (daysDiff <= 1) {
            // Single click: FullCalendar gives end = start + 1, set end = start for UI
            endValue = startValue;
          } else {
            // Drag multiple days: FullCalendar gives end = actual end + 1, subtract 1 for UI
            const adjustedEndDate = new Date(endDateObj);
            adjustedEndDate.setDate(adjustedEndDate.getDate() - 1);
            endValue = adjustedEndDate.toISOString().split("T")[0];
          }
        }

        setStart(startValue);
        setEnd(endValue);

        // Check if multiple days event
        const startDateOnly = startValue.slice(0, 10);
        const endDateOnly = endValue.slice(0, 10);
        const isMultipleDays = startDateOnly !== endDateOnly;

        if (isMultipleDays) {
          // Keep normal mode (showMore = false) for multiple days events
          setShowMore(false);

          if (selectedRange.allDay) {
            // Dragged from allday slot: allday already set to true at line 234
            // Will show start date and end date (handled by showEndDate logic)
          } else {
            // Dragged from week/month view grid: keep allday=false to show time fields, trigger 4 fields display
            setHasEndDateChanged(true);
          }
        }
      } else {
        // Fallback: format Date objects using local time components
        // Only set if both start and end are valid
        const formattedStart = formatLocalDateTime(selectedRange.start);
        let formattedEnd = formatLocalDateTime(selectedRange.end);

        // For all-day slots: detect single click vs drag multiple days
        // FullCalendar uses exclusive end, so end date = actual end date + 1
        // For UI display, we need to adjust:
        // - Single click (end = start + 1): set end = start for UI
        // - Drag multiple days (end = actual end + 1): set end = end - 1 for UI
        if (selectedRange.allDay && formattedStart && formattedEnd) {
          const startDateOnly = formattedStart.slice(0, 10);
          const endDateOnly = formattedEnd.slice(0, 10);

          // Calculate days difference
          const startDateObj = new Date(startDateOnly);
          const endDateObj = new Date(endDateOnly);
          const daysDiff = Math.floor(
            (endDateObj.getTime() - startDateObj.getTime()) /
              (1000 * 60 * 60 * 24)
          );

          if (daysDiff <= 1) {
            // Single click: FullCalendar gives end = start + 1, set end = start for UI
            formattedEnd = formattedStart;
          } else {
            // Drag multiple days: FullCalendar gives end = actual end + 1, subtract 1 for UI
            const adjustedEndDate = new Date(endDateObj);
            adjustedEndDate.setDate(adjustedEndDate.getDate() - 1);
            const adjustedEndDateStr = adjustedEndDate
              .toISOString()
              .split("T")[0];
            // Preserve time part if exists, otherwise use date only
            formattedEnd = formattedEnd.includes("T")
              ? `${adjustedEndDateStr}T${formattedEnd.split("T")[1]}`
              : adjustedEndDateStr;
          }
        }

        if (formattedStart) setStart(formattedStart);
        if (formattedEnd) setEnd(formattedEnd);
        if (formattedStart && formattedEnd) {
          const startDateOnly = formattedStart.slice(0, 10);
          const endDateOnly = formattedEnd.slice(0, 10);
          const isMultipleDays = startDateOnly !== endDateOnly;

          if (isMultipleDays) {
            // Keep normal mode (showMore = false) for multiple days events
            setShowMore(false);

            if (selectedRange.allDay) {
              // Dragged from allday slot: allday already set to true at line 234
              // Will show start date and end date (handled by showEndDate logic)
            } else {
              // Dragged from week/month view grid: keep allday=false to show time fields, trigger 4 fields display
              setHasEndDateChanged(true);
            }
          }
        }
      }
    } else {
      // No valid selectedRange - use default times
      // Start time = current time + 1 hour (rounded up to the hour)
      // End time = start time + 1 hour
      const now = new Date();
      const nextHour = new Date(now);
      nextHour.setHours(now.getHours() + 1);
      nextHour.setMinutes(0);
      nextHour.setSeconds(0);
      nextHour.setMilliseconds(0);

      const endTime = new Date(nextHour);
      endTime.setHours(nextHour.getHours() + 1);

      // Format using local time (browser timezone)
      const formattedStart = formatLocalDateTime(nextHour);
      const formattedEnd = formatLocalDateTime(endTime);

      if (formattedStart) setStart(formattedStart);
      if (formattedEnd) setEnd(formattedEnd);

      // Default to non-all-day when no selectedRange
      setAllDay(false);
    }

    shouldSyncFromRangeRef.current = false;
  }, [selectedRange, open, event]);

  // Initialize state when event prop changes (duplicate event or tempEvent with attendees)
  useEffect(() => {
    if (event && event.uid) {
      // Editing existing event - populate fields with event data
      setTitle(event.title ?? "");
      setDescription(event.description ?? "");
      setLocation(event.location ?? "");

      // Handle all-day events properly
      const isAllDay = event.allday ?? false;
      setAllDay(isAllDay);

      // Get event's timezone for formatting - prioritize event.timezone from server
      let eventTimezone: string;
      if (event.timezone) {
        eventTimezone = resolveTimezone(event.timezone);
      } else {
        eventTimezone = resolvedCalendarTimezone;
      }

      // Format dates based on all-day status and timezone
      if (event.start) {
        if (isAllDay) {
          // For all-day events, use date format (YYYY-MM-DD)
          const startDate = new Date(event.start);
          setStart(startDate.toISOString().split("T")[0]);
        } else {
          // For timed events, format in the event's timezone
          setStart(formatDateTimeInTimezone(event.start, eventTimezone));
        }
      } else {
        setStart("");
      }

      if (event.end) {
        if (isAllDay) {
          // For all-day events, use date format (YYYY-MM-DD)
          const endDate = new Date(event.end);
          setEnd(endDate.toISOString().split("T")[0]);
        } else {
          // For timed events, format in the event's timezone
          setEnd(formatDateTimeInTimezone(event.end, eventTimezone));
        }
      } else {
        setEnd("");
      }

      if (defaultCalendarId) {
        setCalendarid(defaultCalendarId);
      }
      setRepetition(event.repetition ?? ({} as RepetitionObject));
      setShowRepeat(event.repetition?.freq ? true : false);
      setAttendees(
        event.attendee
          ? event.attendee.filter(
              (a) => a.cal_address !== organizer?.cal_address
            )
          : []
      );
      setAlarm(event.alarm?.trigger ?? "");
      setEventClass(event.class ?? "PUBLIC");
      setBusy(event.transp ?? "OPAQUE");
      setTimezone(eventTimezone);
      setHasVideoConference(event.x_openpass_videoconference ? true : false);
      setMeetingLink(event.x_openpass_videoconference || null);

      // Update description to include video conference footer if exists
      if (event.x_openpass_videoconference && event.description) {
        const hasVideoFooter = event.description.includes("Visio:");
        if (!hasVideoFooter) {
          setDescription(
            addVideoConferenceToDescription(
              event.description,
              event.x_openpass_videoconference
            )
          );
        } else {
          setDescription(event.description);
        }
      }
    } else if (event && event.attendee && event.attendee.length > 0) {
      // Handle tempEvent case (no uid but has attendees from temp calendar search)
      setAttendees(
        event.attendee.filter((a) => a.cal_address !== organizer?.cal_address)
      );
    }
  }, [
    event,
    organizer?.cal_address,
    resolvedCalendarTimezone,
    defaultCalendarId,
  ]);

  // Reset state when creating new event (event is empty object or undefined)
  useEffect(() => {
    // Skip if restoring from error - data already restored
    if (isRestoringFromErrorRef.current) {
      return;
    }
    const isCreatingNew = !event || !event.uid;
    const wasInitialized = isInitializedRef.current;

    if (isCreatingNew && wasInitialized) {
      // Creating new event - reset all fields to default
      // Note: start and end are handled by the selectedRange useEffect
      // Note: timezone is handled by separate useEffect above
      setShowMore(false);
      setShowDescription(false);
      setShowRepeat(false);
      setTitle("");
      setDescription("");
      setAttendees([]);
      setLocation("");
      if (defaultCalendarId) {
        setCalendarid(defaultCalendarId);
      }
      setAllDay(false);
      setRepetition({} as RepetitionObject);
      setAlarm("");
      setEventClass("PUBLIC");
      setBusy("OPAQUE");
      setHasVideoConference(false);
      setMeetingLink(null);
      setHasEndDateChanged(false);
    }

    if (!isCreatingNew) {
      isInitializedRef.current = true;
    }
  }, [event, defaultCalendarId]);

  const handleStartChange = useCallback(
    (newStart: string) => {
      setStart(newStart);

      // Defer visual feedback (non-urgent)
      startTransition(() => {
        setSelectedRange((prev: DateSelectArg | null) => {
          const newRange = {
            ...prev,
            start: new Date(newStart),
            startStr: newStart,
            allDay: allday,
          } as DateSelectArg;
          setTimeout(() => {
            calendarRef.current?.select(newRange);
          }, 0);
          return newRange;
        });
      });
    },
    // calendarRef and setSelectedRange are stable refs/setters from parent
    // eslint-disable-next-line react-hooks/exhaustive-deps
    [allday]
  );

  const handleEndChange = useCallback(
    (newEnd: string) => {
      setEnd(newEnd);

      // Defer visual feedback (non-urgent)
      startTransition(() => {
        setSelectedRange((prev: DateSelectArg | null) => {
          const newRange = {
            ...prev,
            end: new Date(newEnd),
            endStr: newEnd,
            allDay: allday,
          } as DateSelectArg;
          setTimeout(() => {
            calendarRef.current?.select(newRange);
          }, 0);
          return newRange;
        });
      });
    },
    // calendarRef and setSelectedRange are stable refs/setters from parent
    // eslint-disable-next-line react-hooks/exhaustive-deps
    [allday]
  );

  const handleAllDayChange = useCallback(
    (newAllDay: boolean, newStart: string, newEnd: string) => {
      // Update critical state immediately (checkbox response)
      setAllDay(newAllDay);
      setStart(newStart);
      setEnd(newEnd);

      // Defer visual feedback updates (non-urgent)
      startTransition(() => {
        setSelectedRange((prev: DateSelectArg | null) => {
          const newRange = {
            ...prev,
            startStr: newAllDay ? newStart.split("T")[0] : newStart,
            endStr: newAllDay ? newEnd.split("T")[0] : newEnd,
            start: new Date(
              newAllDay ? newStart.split("T")[0] + "T00:00:00" : newStart
            ),
            end: new Date(
              newAllDay ? newEnd.split("T")[0] + "T00:00:00" : newEnd
            ),
            allDay: newAllDay,
          } as DateSelectArg;
          setTimeout(() => {
            calendarRef.current?.select(newRange);
          }, 0);
          return newRange;
        });
      });
    },
    // calendarRef and setSelectedRange are stable refs/setters from parent
    // eslint-disable-next-line react-hooks/exhaustive-deps
    []
  );

  // Wrap setCalendarid so we can track explicit user selections
  const handleCalendaridChange = useCallback((id: string) => {
    isCalendarIdUserSelectedRef.current = true;
    setCalendarid(id);
  }, []);

  const handleClose = () => {
    // Clear temp data when user manually closes modal
    clearEventFormTempData("create");
    onClose(false);
    setShowValidationErrors(false);
    resetAllStateToDefault();
    setStart("");
    setEnd("");
    shouldSyncFromRangeRef.current = true; // Reset for next time
    isCalendarIdUserSelectedRef.current = false; // Reset so next open gets fresh default
  };

  // Function to save current form data to temp storage
  const saveCurrentFormData = useCallback(() => {
    const formState: EventFormState = {
      title,
      description,
      location,
      start,
      end,
      allday,
      repetition,
      attendees,
      alarm,
      busy,
      eventClass,
      timezone,
      calendarid,
      hasVideoConference,
      meetingLink,
      showMore,
      showDescription,
      showRepeat,
      hasEndDateChanged,
    };
    return buildEventFormTempData(formState);
  }, [
    title,
    description,
    location,
    start,
    end,
    allday,
    repetition,
    attendees,
    alarm,
    busy,
    eventClass,
    timezone,
    calendarid,
    hasVideoConference,
    meetingLink,
    showMore,
    showDescription,
    showRepeat,
    hasEndDateChanged,
  ]);

  // Check for temp data when modal opens
  useEffect(() => {
    if (open && !event?.uid) {
      // Only restore for new events (not duplicating)
      const tempData = restoreEventFormDataFromStorage("create");
      if (tempData && tempData.fromError) {
        // Mark that we're restoring from error to prevent other useEffects from overriding
        isRestoringFromErrorRef.current = true;
        // Prevent selectedRange useEffect from running
        shouldSyncFromRangeRef.current = false;

        // Restore form data from previous failed save
        restoreFormDataFromTemp(tempData, {
          setTitle,
          setDescription,
          setLocation,
          setStart,
          setEnd,
          setAllDay,
          setRepetition,
          setAttendees,
          setAlarm,
          setBusy,
          setEventClass,
          setTimezone,
          setCalendarid,
          setHasVideoConference,
          setMeetingLink,
          setShowMore,
          setShowDescription,
          setShowRepeat,
          setHasEndDateChanged,
        });
        // Clear the error flag but keep data until successful save
        const updatedTempData = { ...tempData, fromError: false };
        saveEventFormDataToTemp("create", updatedTempData);

        // Reset flag after restore completes (use setTimeout to ensure other useEffects have checked the flag)
        setTimeout(() => {
          isRestoringFromErrorRef.current = false;
        }, 0);
      }
    }
  }, [open, event?.uid]);

  const handleSave = async () => {
    // Show validation errors when Save is clicked
    setShowValidationErrors(true);

    // Check if form is valid before saving
    if (!isFormValid) {
      return;
    }
    const newEventUID = crypto.randomUUID();

    // Resolve target calendar safely
    const targetCalendar: Calendar | undefined =
      calList[calendarid] ||
      userPersonalCalendars[0] ||
      (Object.values(calList)[0] as Calendar | undefined);
    if (!targetCalendar || !targetCalendar.id) {
      console.error("No target calendar available to save event");
      return;
    }
    const newEventURL = `/calendars/${targetCalendar.id}/${newEventUID}.ics`;
    const newEvent: CalendarEvent = {
      calId: targetCalendar.id,
      title,
      URL: targetCalendar.delegated
        ? buildDelegatedEventURL(targetCalendar, newEventURL)
        : newEventURL,
      start: "",
      allday,
      uid: newEventUID,
      description,
      location,
      class: eventClass,
      repetition,
      organizer,
      timezone,
      attendee: [
        {
          cn: organizer?.cn ?? "",
          cal_address: organizer?.cal_address ?? "",
          partstat: "ACCEPTED",
          rsvp: "FALSE",
          role: "CHAIR",
          cutype: "INDIVIDUAL",
        },
      ],
      transp: busy,
      sequence: 1,
      color: targetCalendar?.color,
      alarm: { trigger: alarm, action: "EMAIL" },
      x_openpass_videoconference: meetingLink || undefined,
    };

    if (allday) {
      const startDateOnly = (start || "").split("T")[0];
      const endDateOnlyUI = (end || start || "").split("T")[0];
      // For all-day events, API needs end date = UI end date + 1 day
      const endDateOnlyAPI = addDays(endDateOnlyUI, 1);
      // Parse date string and create Date at UTC midnight to avoid timezone offset issues
      const [startYear, startMonth, startDay] = startDateOnly
        .split("-")
        .map(Number);
      const [endYear, endMonth, endDay] = endDateOnlyAPI.split("-").map(Number);
      const startDateObj = new Date(
        Date.UTC(startYear, startMonth - 1, startDay, 0, 0, 0, 0)
      );
      const endDateObj = new Date(
        Date.UTC(endYear, endMonth - 1, endDay, 0, 0, 0, 0)
      );
      newEvent.start = startDateObj.toISOString();
      newEvent.end = endDateObj.toISOString();
    } else {
      newEvent.start = convertFormDateTimeToISO(start, timezone);
      if (end) {
        // In normal mode, only override end date when the end date field is not shown and end date is same as start date
        const startDateOnly = (start || "").split("T")[0];
        const endDateOnly = (end || "").split("T")[0];
        if (!showMore && !hasEndDateChanged && startDateOnly === endDateOnly) {
          const endTimeOnly = end.includes("T")
            ? end.split("T")[1]?.slice(0, 5) || "00:00"
            : "00:00";
          const endDateTime = `${startDateOnly}T${endTimeOnly}`;
          newEvent.end = convertFormDateTimeToISO(endDateTime, timezone);
        } else {
          // Extended mode or end date explicitly shown in normal mode or end date differs from start date: use actual end datetime
          newEvent.end = convertFormDateTimeToISO(end, timezone);
        }
      }
    }

    if (attendees.length > 0) {
      newEvent.attendee = newEvent.attendee.concat(attendees);
    }

    // Reset validation state when validation passes
    setShowValidationErrors(false);

    // Save current form data to temp storage before closing
    const formDataToSave = saveCurrentFormData();
    saveEventFormDataToTemp("create", formDataToSave);

    // Close popup immediately
    onClose(true);

    // Save to API in background
    try {
      const result = await dispatch(
        putEventAsync({
          cal: targetCalendar,
          newEvent,
        })
      );

      await assertThunkSuccess(result);

      // Clear temp data on successful save
      clearEventFormTempData("create");

      // Reset all state to default values only on successful save
      resetAllStateToDefault();
    } catch (error) {
      const errorObj = error as { message?: string };

      // API failed - restore form data and mark as error
      const errorFormData = {
        ...formDataToSave,
        fromError: true,
      };
      saveEventFormDataToTemp("create", errorFormData);

      // Show error notification
      showErrorNotification(
        errorObj.message || "Failed to create event. Please try again."
      );

      // Try to reopen modal by dispatching custom event
      // Parent component should listen to this event and reopen modal
      window.dispatchEvent(
        new CustomEvent("eventModalError", {
          detail: { type: "create" },
        })
      );
    }
  };

  const dialogActions = (
    <Box display="flex" justifyContent="space-between" width="100%" px={2}>
      {!showMore && (
        <Button startIcon={<AddIcon />} onClick={() => setShowMore(!showMore)}>
          {t("common.moreOptions")}
        </Button>
      )}
      <Box display="flex" gap={1} ml={showMore ? "auto" : 0}>
        {showMore && (
          <Button variant="outlined" onClick={handleClose}>
            {t("common.cancel")}
          </Button>
        )}
        <Button variant="contained" onClick={handleSave}>
          {t("actions.save")}
        </Button>
      </Box>
    </Box>
  );

  return (
    <ResponsiveDialog
      open={open}
      onClose={handleClose}
      title={
        event?.uid
          ? t("eventDuplication.duplicateEvent")
          : t("event.createEvent")
      }
      isExpanded={showMore}
      onExpandToggle={() => setShowMore(!showMore)}
      actions={dialogActions}
    >
      <EventFormFields
        title={title}
        setTitle={setTitle}
        description={description}
        setDescription={setDescription}
        location={location}
        setLocation={setLocation}
        start={start}
        setStart={setStart}
        end={end}
        setEnd={setEnd}
        allday={allday}
        setAllDay={setAllDay}
        repetition={repetition}
        setRepetition={setRepetition}
        attendees={attendees}
        setAttendees={setAttendees}
        alarm={alarm}
        setAlarm={setAlarm}
        busy={busy}
        setBusy={setBusy}
        eventClass={eventClass}
        setEventClass={setEventClass}
        timezone={timezone}
        setTimezone={setTimezone}
        calendarid={calendarid}
        setCalendarid={handleCalendaridChange}
        hasVideoConference={hasVideoConference}
        setHasVideoConference={setHasVideoConference}
        meetingLink={meetingLink}
        setMeetingLink={setMeetingLink}
        showMore={showMore}
        showDescription={showDescription}
        setShowDescription={setShowDescription}
        showRepeat={showRepeat}
        setShowRepeat={setShowRepeat}
        isOpen={open}
        userPersonalCalendars={userPersonalCalendars}
        timezoneList={timezoneList}
        onStartChange={handleStartChange}
        onEndChange={handleEndChange}
        onAllDayChange={handleAllDayChange}
        onValidationChange={setIsFormValid}
        showValidationErrors={showValidationErrors}
        onHasEndDateChangedChange={setHasEndDateChanged}
      />
    </ResponsiveDialog>
  );
}

export default EventPopover;
