import { ImportICSModal } from "@ui/components/ImportICSModal";
import { WebcalModal } from "@ui/components/WebcalModal";
import { downloadICSFile, generateICSFromEvents, toast } from "@xtablo/shared";
import { EventAndTablo } from "@xtablo/shared/types/events.types";
import { Button } from "@xtablo/ui/components/button";
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuSeparator,
  DropdownMenuTrigger,
} from "@xtablo/ui/components/dropdown-menu";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@xtablo/ui/components/select";
import { TypographyH3, TypographyH4 } from "@xtablo/ui/components/typography";
import {
  ClockIcon,
  Compass,
  Download,
  EllipsisVerticalIcon,
  Flame,
  FolderIcon,
  FolderInputIcon,
  Gem,
  Heart,
  Leaf,
  PlusIcon,
  RefreshCcw,
  Sparkles,
  Star,
  Sun,
  Waves,
  Zap,
} from "lucide-react";
import { useCallback, useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { Outlet, useNavigate, useParams, useSearchParams } from "react-router-dom";
import { EventModal } from "../components/EventModal";
import { useDeleteEvent, useEventsByTablo } from "../hooks/events";
import { useGetAllTabloAccess, useTablosList } from "../hooks/tablos";
import { useIsReadOnlyUser } from "../providers/UserStoreProvider";

type ViewType = "month" | "week" | "day";

function getTabloIcon(color: string | null | undefined) {
  switch (color) {
    case "bg-blue-500":
      return Zap;
    case "bg-green-500":
      return Leaf;
    case "bg-purple-500":
      return Gem;
    case "bg-red-500":
      return Flame;
    case "bg-yellow-500":
      return Star;
    case "bg-indigo-500":
      return Compass;
    case "bg-pink-500":
      return Heart;
    case "bg-teal-500":
      return Waves;
    case "bg-orange-500":
      return Sun;
    case "bg-cyan-500":
      return Sparkles;
    default:
      return FolderIcon;
  }
}

function getTabloIconColor(color: string | null | undefined): string {
  switch (color) {
    case "bg-yellow-500":
    case "bg-cyan-500":
      return "text-gray-700";
    default:
      return "text-white";
  }
}

export const PlanningPage = () => {
  const { t } = useTranslation(["planning", "common"]);
  const { tablo_id } = useParams();
  const navigate = useNavigate();
  const [searchParams, setSearchParams] = useSearchParams();
  const [currentDate, setCurrentDate] = useState(new Date());
  // const [selectedDate, setSelectedDate] = useState(new Date());

  // Initialize view from URL search params, default to "month"
  const viewFromUrl = searchParams.get("view") as ViewType | null;
  const initialView: ViewType =
    viewFromUrl && ["month", "week", "day"].includes(viewFromUrl) ? viewFromUrl : "month";
  const [currentView, setCurrentView] = useState<ViewType>(initialView);

  const [selectedTabloId, setSelectedTabloId] = useState<string>(tablo_id || "all");
  const [isImportModalOpen, setIsImportModalOpen] = useState(false);
  const [isWebcalModalOpen, setIsWebcalModalOpen] = useState(false);
  const isReadOnly = useIsReadOnlyUser();
  const currentTab = searchParams.get("tab") ?? "calendar";
  const [showAllEvents, setShowAllEvents] = useState(false);
  const [isCreateEventOpen, setIsCreateEventOpen] = useState(false);

  // Fetch tablos
  const { data: tablos, isLoading: tablosLoading } = useTablosList();

  // Fetch events for selected tablo or all tablos
  const { data: tabloEvents = [], isLoading: tabloEventsLoading } = useEventsByTablo(
    selectedTabloId !== "all" ? selectedTabloId : null
  );
  // Fetch all tablo accesses
  const { data: tabloAccess } = useGetAllTabloAccess();

  const deleteEvent = useDeleteEvent();

  // Check if an event can be deleted (e.g., based on permissions, event status, etc.)
  const canDeleteEvent = (event: EventAndTablo) => {
    if (
      tabloAccess?.find(
        (access: { tablo_id: string; is_admin: boolean }) =>
          access.tablo_id === event.tablo_id && access.is_admin
      )
    ) {
      return true;
    }
    return false;
  };

  // Check if an event can be edited (same logic as delete - admin access required)
  const canEditEvent = (event: EventAndTablo) => {
    return canDeleteEvent(event);
  };

  // Function to change view and update URL
  const changeView = useCallback(
    (newView: ViewType) => {
      setCurrentView(newView);
      setSearchParams((params) => {
        const newParams = new URLSearchParams(params);
        newParams.set("view", newView);
        return newParams;
      });
    },
    [setSearchParams]
  );

  // Sync view with URL on mount and when URL changes
  useEffect(() => {
    const viewParam = searchParams.get("view") as ViewType | null;
    if (viewParam && ["month", "week", "day"].includes(viewParam) && viewParam !== currentView) {
      setCurrentView(viewParam);
    } else if (!viewParam) {
      // If no view param in URL, set it to current view
      setSearchParams(
        (params) => {
          const newParams = new URLSearchParams(params);
          newParams.set("view", currentView);
          return newParams;
        },
        { replace: true }
      );
    }
  }, [searchParams, currentView, setSearchParams]);

  // Keyboard shortcuts for view switching
  useEffect(() => {
    const handleKeyPress = (event: KeyboardEvent) => {
      // Only trigger shortcuts when not typing in input fields
      if (
        event.target instanceof HTMLInputElement ||
        event.target instanceof HTMLTextAreaElement ||
        event.target instanceof HTMLSelectElement
      ) {
        return;
      }

      // Prevent default behavior and switch views
      switch (event.key.toLowerCase()) {
        case "m":
        case "1":
          event.preventDefault();
          changeView("month");
          break;
        case "w":
        case "s":
        case "2":
          event.preventDefault();
          changeView("week");
          break;
        case "d":
        case "j":
        case "3":
          event.preventDefault();
          changeView("day");
          break;
      }
    };

    window.addEventListener("keydown", handleKeyPress);
    return () => window.removeEventListener("keydown", handleKeyPress);
  }, [changeView]);

  const handleExportICS = () => {
    if (!tabloEvents || tabloEvents.length === 0) {
      return;
    }

    const calendarName =
      selectedTabloId === "all"
        ? t("planning:allEvents")
        : tablos?.find((t) => t.id === selectedTabloId)?.name || t("planning:title");

    const icsContent = generateICSFromEvents(tabloEvents, calendarName);
    const filename =
      selectedTabloId === "all"
        ? "planning-tous-tablos.ics"
        : `planning-${tablos?.find((t) => t.id === selectedTabloId)?.name || "tablo"}.ics`;

    downloadICSFile(icsContent, filename);
  };

  const navigateToCreateEvent = (date: Date, tablo_id: string) => {
    if (tablo_id === "all") {
      navigate({
        pathname: "/planning/create",
        search: `date=${date.toISOString()}`,
      });
    } else {
      navigate({
        pathname: "/planning/create",
        search: `date=${date.toISOString()}&tablo_id=${tablo_id}`,
      });
    }
  };

  const navigateToEditEvent = (event: EventAndTablo) => {
    if (!canEditEvent(event) || isReadOnly) return;

    const params = new URLSearchParams(searchParams);
    params.set("tab", "events");

    navigate({
      pathname: `/planning/${event.tablo_id}/events/${event.event_id}/edit`,
      search: `?${params.toString()}`,
    });
  };

  const monthNames = [
    t("planning:months.january"),
    t("planning:months.february"),
    t("planning:months.march"),
    t("planning:months.april"),
    t("planning:months.may"),
    t("planning:months.june"),
    t("planning:months.july"),
    t("planning:months.august"),
    t("planning:months.september"),
    t("planning:months.october"),
    t("planning:months.november"),
    t("planning:months.december"),
  ];

  const dayNames = [
    t("planning:days.sunday"),
    t("planning:days.monday"),
    t("planning:days.tuesday"),
    t("planning:days.wednesday"),
    t("planning:days.thursday"),
    t("planning:days.friday"),
    t("planning:days.saturday"),
  ];
  const dayNamesShort = [
    t("planning:days.mondayShort"),
    t("planning:days.tuesdayShort"),
    t("planning:days.wednesdayShort"),
    t("planning:days.thursdayShort"),
    t("planning:days.fridayShort"),
    t("planning:days.saturdayShort"),
    t("planning:days.sundayShort"),
  ];

  const formatDate = (date: Date) => {
    // Use local timezone instead of UTC to avoid timezone issues
    const year = date.getFullYear();
    const month = (date.getMonth() + 1).toString().padStart(2, "0");
    const day = date.getDate().toString().padStart(2, "0");
    return `${year}-${month}-${day}`;
  };

  const formatTime = (time: string) => {
    // Remove seconds from time string (HH:MM:SS -> HH:MM)
    return time.substring(0, 5);
  };

  const calculateEventHeight = (startTime: string, endTime: string) => {
    if (!endTime) return 60; // Default height if no end time

    const [startHour, startMinute] = startTime.split(":").map(Number);
    const [endHour, endMinute] = endTime.split(":").map(Number);

    const startTotalMinutes = startHour * 60 + startMinute;
    const endTotalMinutes = endHour * 60 + endMinute;

    const durationMinutes = endTotalMinutes - startTotalMinutes;

    // Each hour is 60px, so calculate proportional height
    return Math.max(durationMinutes, 30); // Minimum 30px height
  };

  const calculateEventOffset = (startTime: string, slotTime: string) => {
    const [startHour, startMinute] = startTime.split(":").map(Number);
    const [slotHour] = slotTime.split(":").map(Number);

    if (startHour === slotHour) {
      // Calculate offset within the hour slot
      return startMinute; // Each minute is 1px
    }

    return 0;
  };

  const getEventsForDate = (date: Date) => {
    const dateString = formatDate(date);
    return tabloEvents.filter((event) => event.start_date === dateString);
  };

  const getCurrentTimePosition = () => {
    const now = new Date();
    const minutes = now.getMinutes();
    // Position within the current hour slot (0-60px based on minutes)
    return minutes;
  };

  const isWithinCurrentHour = (fullDate: Date, time: string) => {
    const now = new Date();
    const nowHour = now.getHours();
    // const nowMinute = now.getMinutes();
    const nowDay = now.getDate();

    fullDate.setHours(Number(time.split(":")[0]), Number(time.split(":")[1]), 0, 0);

    const hour = fullDate.getHours();
    // const minute = fullDate.getMinutes();
    const day = fullDate.getDate();

    return nowDay === day && nowHour === hour;
  };

  const navigateDate = (direction: number) => {
    const newDate = new Date(currentDate);
    if (currentView === "month") {
      newDate.setMonth(newDate.getMonth() + direction);
    } else if (currentView === "week") {
      newDate.setDate(newDate.getDate() + direction * 7);
    } else {
      newDate.setDate(newDate.getDate() + direction);
    }
    setCurrentDate(newDate);
  };

  const goToToday = () => {
    const today = new Date();
    setCurrentDate(today);
  };

  const getViewTitle = () => {
    if (currentView === "month") {
      return `${monthNames[currentDate.getMonth()]} ${currentDate.getFullYear()}`;
    } else if (currentView === "week") {
      const startOfWeek = new Date(currentDate);
      // Get Monday as first day (0=Sunday, 1=Monday, etc.)
      const dayOfWeek = currentDate.getDay();
      const daysFromMonday = dayOfWeek === 0 ? 6 : dayOfWeek - 1;
      startOfWeek.setDate(currentDate.getDate() - daysFromMonday);
      const endOfWeek = new Date(startOfWeek);
      endOfWeek.setDate(startOfWeek.getDate() + 6);

      if (startOfWeek.getMonth() === endOfWeek.getMonth()) {
        return `${monthNames[startOfWeek.getMonth()]} ${startOfWeek.getFullYear()}`;
      } else if (startOfWeek.getFullYear() !== endOfWeek.getFullYear()) {
        const startMonth = monthNames[startOfWeek.getMonth()].slice(0, 3);
        const endMonth = monthNames[endOfWeek.getMonth()].slice(0, 3);
        return `${startMonth} ${startOfWeek.getFullYear()} - ${endMonth} ${endOfWeek.getFullYear()}`;
      } else {
        const startMonth = monthNames[startOfWeek.getMonth()].slice(0, 3);
        const endMonth = monthNames[endOfWeek.getMonth()].slice(0, 3);
        return `${startMonth} - ${endMonth} ${endOfWeek.getFullYear()}`;
      }
    } else {
      const dateString = currentDate.toLocaleDateString("fr-FR", {
        weekday: "long",
        year: "numeric",
        month: "long",
        day: "numeric",
      });
      return dateString.charAt(0).toUpperCase() + dateString.slice(1);
    }
  };

  const getDaysInMonth = (date: Date) => {
    const year = date.getFullYear();
    const month = date.getMonth();
    const firstDay = new Date(year, month, 1);
    const lastDay = new Date(year, month + 1, 0);
    const daysInMonth = lastDay.getDate();
    // Adjust for Monday as first day of week
    const startingDayOfWeek = firstDay.getDay();
    const mondayStartingDay = startingDayOfWeek === 0 ? 6 : startingDayOfWeek - 1;

    const days = [];
    for (let i = 0; i < mondayStartingDay; i++) {
      days.push(null);
    }
    for (let day = 1; day <= daysInMonth; day++) {
      days.push(new Date(year, month, day));
    }
    return days;
  };

  const getWeekDays = () => {
    const startOfWeek = new Date(currentDate);
    // Get Monday as first day (0=Sunday, 1=Monday, etc.)
    const dayOfWeek = currentDate.getDay();
    const daysFromMonday = dayOfWeek === 0 ? 6 : dayOfWeek - 1; // Sunday = 6 days from Monday
    startOfWeek.setDate(currentDate.getDate() - daysFromMonday);

    const weekDays = [];
    for (let i = 0; i < 7; i++) {
      const day = new Date(startOfWeek);
      day.setDate(startOfWeek.getDate() + i);
      weekDays.push(day);
    }
    return weekDays;
  };

  // Get visible events for the current view
  const getVisibleEvents = () => {
    if (currentView === "month") {
      return [];
    }

    if (currentView === "week") {
      const weekDays = getWeekDays();
      const weekDateStrings = weekDays.map(formatDate);
      return tabloEvents.filter((event) => weekDateStrings.includes(event.start_date));
    } else if (currentView === "day") {
      const dateString = formatDate(currentDate);
      return tabloEvents.filter((event) => event.start_date === dateString);
    }

    return [];
  };

  // Get the earliest event hour from visible events in the current view
  const getEarliestEventHour = () => {
    const visibleEvents = getVisibleEvents();

    if (visibleEvents.length === 0) {
      return 8; // Default to 8am if no events
    }

    const earliestHour = Math.min(
      ...visibleEvents.map((event) => {
        const [hour] = event.start_time.split(":").map(Number);
        return hour;
      })
    );

    // Return the earlier of 8am or the earliest event hour
    return Math.min(8, earliestHour);
  };

  // Get the latest event hour from visible events in the current view
  const getLatestEventHour = () => {
    const visibleEvents = getVisibleEvents();

    if (visibleEvents.length === 0) {
      return 19; // Default to 7pm if no events
    }

    const latestHour = Math.max(
      ...visibleEvents.map((event) => {
        if (!event.end_time) {
          // If no end time, use start time + 1 hour
          const [hour] = event.start_time.split(":").map(Number);
          return hour + 1;
        }
        const [hour] = event.end_time.split(":").map(Number);
        return hour;
      })
    );

    // Return the later of 7pm or the latest event hour
    return Math.max(19, latestHour);
  };

  // Generate time slots based on view type
  const getTimeSlots = () => {
    if (currentView === "month") {
      // Month view doesn't use time slots
      return [];
    }

    const earliestEventHour = getEarliestEventHour();
    const latestEventHour = getLatestEventHour();

    // Add buffer: start 1 hour before earliest event (but not before 6am)
    const startHour = Math.max(6, earliestEventHour - 1);

    // Add buffer: end 1 hour after latest event (but not after midnight)
    const endHour = Math.min(24, latestEventHour + 1);

    const numSlots = endHour - startHour;

    return Array.from(
      { length: numSlots },
      (_, i) => `${(startHour + i).toString().padStart(2, "0")}:00`
    );
  };

  const timeSlots = getTimeSlots();

  const renderMonthView = () => (
    <div className="flex-1 bg-card border border-border">
      {/* Days header */}
      <div className="grid grid-cols-7 border-b border-border">
        {dayNamesShort.map((day) => (
          <div
            key={day}
            className="p-4 text-center text-sm font-medium text-muted-foreground border-r border-border last:border-r-0"
          >
            {day}
          </div>
        ))}
      </div>

      {/* Calendar grid */}
      <div className="grid grid-cols-7">
        {getDaysInMonth(currentDate).map((day, index) => (
          <div
            key={index}
            className={`min-h-[120px] border-b border-border ${
              (index + 1) % 7 !== 0 ? "border-r border-border" : ""
            } ${day ? "cursor-pointer hover:bg-muted" : "bg-muted"} ${
              day && formatDate(day) === formatDate(new Date()) ? "bg-primary/10" : ""
            }`}
            onClick={() => {
              if (day) {
                navigate({
                  pathname: "/planning/create",
                  search:
                    selectedTabloId === "all"
                      ? `?date=${day.toISOString()}`
                      : `?date=${day.toISOString()}&tablo_id=${selectedTabloId}`,
                });
              }
            }}
          >
            {day && (
              <div className="p-2">
                <div
                  className={`text-sm font-medium mb-1 ${
                    formatDate(day) === formatDate(new Date()) ? "text-primary" : "text-foreground"
                  }`}
                >
                  {day.getDate()}
                </div>
                <div className="space-y-1">
                  {getEventsForDate(day)
                    .sort((a, b) => a.start_time.localeCompare(b.start_time))
                    .slice(0, 3)
                    .map((event) => (
                      <div
                        key={event.event_id}
                        className={`text-[10px] px-1.5 py-1 rounded text-white ${
                          event.tablo_color
                        } truncate group relative leading-tight ${
                          canEditEvent(event)
                            ? "cursor-pointer hover:opacity-80"
                            : "cursor-default opacity-75"
                        }`}
                        title={`${formatTime(event.start_time)} ${event.title}${
                          selectedTabloId === "all" && event.tablo_name
                            ? ` - ${event.tablo_name}`
                            : ""
                        }${!canEditEvent(event) ? " (Lecture seule)" : ""}`}
                        onClick={(e) => {
                          e.stopPropagation();
                          if (canEditEvent(event)) {
                            navigate(`/planning/${event.tablo_id}/events/${event.event_id}/edit`);
                          }
                        }}
                      >
                        <div className="truncate">
                          {formatTime(event.start_time)} {event.title}
                          {selectedTabloId === "all" && event.tablo_name && (
                            <span className="opacity-75 ml-1">• {event.tablo_name}</span>
                          )}
                        </div>
                        {canDeleteEvent(event) && (
                          <button
                            onClick={(e) => {
                              e.stopPropagation();
                              deleteEvent.mutate(event.event_id);
                            }}
                            className="absolute -top-1 -right-1 w-5 h-5 bg-destructive text-destructive-foreground rounded-full opacity-0 group-hover:opacity-100 transition-all text-sm flex items-center justify-center hover:scale-110 shadow-sm"
                            title="Supprimer l'événement"
                          >
                            ×
                          </button>
                        )}
                      </div>
                    ))}
                  {getEventsForDate(day).length > 3 && (
                    <div className="text-xs text-muted-foreground px-2">
                      +{getEventsForDate(day).length - 3} autres
                    </div>
                  )}
                </div>
              </div>
            )}
          </div>
        ))}
      </div>
    </div>
  );

  const renderWeekView = () => (
    <div className="flex-1 bg-card border border-border flex flex-col">
      {/* Week header */}
      <div className="flex border-b border-border">
        <div className="w-20 p-4 border-r border-border shrink-0"></div>
        {getWeekDays().map((day, index) => (
          <div
            key={day.toISOString()}
            className={`flex-1 p-4 text-center border-r border-border ${
              index === 6 ? "border-r-0" : ""
            }`}
          >
            <div className="text-xs text-muted-foreground uppercase">
              {dayNamesShort[day.getDay() === 0 ? 6 : day.getDay() - 1]}
            </div>
            <div
              className={`text-lg font-medium mt-1 ${
                formatDate(day) === formatDate(new Date()) ? "text-primary" : "text-foreground"
              }`}
            >
              {day.getDate()}
            </div>
          </div>
        ))}
      </div>

      {/* Time slots */}
      <div className="flex-1 overflow-y-auto">
        {timeSlots.map((time) => (
          <div key={time} className="flex border-b border-border">
            <div className="w-20 p-2 text-xs text-muted-foreground text-right border-r border-border shrink-0">
              {time}
            </div>
            {getWeekDays().map((day, index) => (
              <div
                key={`${day.toISOString()}-${time}`}
                className={`flex-1 min-h-[60px] border-r border-border hover:bg-muted cursor-pointer relative ${
                  index === 6 ? "border-r-0" : ""
                }`}
                onClick={() => {
                  const [hour] = time.split(":").map(Number);
                  const dateWithTime = new Date(day);
                  dateWithTime.setHours(hour, 0, 0, 0);
                  navigateToCreateEvent(dateWithTime, selectedTabloId);
                }}
              >
                {/* Current time indicator for today */}
                {isWithinCurrentHour(day, time) && (
                  <div
                    className="absolute left-0 right-0 h-0.5 bg-destructive z-20 pointer-events-none"
                    style={{
                      top: `${getCurrentTimePosition()}px`,
                    }}
                  >
                    <div className="absolute -left-1 -top-1 w-2 h-2 bg-destructive rounded-full"></div>
                  </div>
                )}

                {getEventsForDate(day)
                  .filter((event) => event.start_time.startsWith(time.split(":")[0]))
                  .map((event) => {
                    const eventHeight = calculateEventHeight(event.start_time, event.end_time);
                    const eventOffset = calculateEventOffset(event.start_time, time);
                    return (
                      <div
                        key={event.event_id}
                        className={`absolute left-1 right-1 p-0.5 rounded text-white ${
                          event.tablo_color
                        } text-xs overflow-hidden z-10 group ${
                          canEditEvent(event)
                            ? "cursor-pointer hover:opacity-90"
                            : "cursor-default opacity-75"
                        }`}
                        style={{
                          top: `${eventOffset}px`,
                          height: `${eventHeight}px`,
                          minHeight: "30px",
                        }}
                        title={`${formatTime(event.start_time)} - ${formatTime(
                          event.end_time
                        )} ${event.title}${
                          selectedTabloId === "all" && event.tablo_name
                            ? ` - ${event.tablo_name}`
                            : ""
                        }${!canEditEvent(event) ? " (Lecture seule)" : ""}`}
                        onClick={(e) => {
                          e.stopPropagation();
                          if (canEditEvent(event)) {
                            navigate(`/planning/${event.tablo_id}/events/${event.event_id}/edit`);
                          }
                        }}
                      >
                        <div className="text-[10px] font-medium leading-tight">
                          {event.title}
                          {selectedTabloId === "all" && event.tablo_name && (
                            <span className="opacity-75 ml-1">• {event.tablo_name}</span>
                          )}
                        </div>
                        {eventHeight >= 30 && (
                          <div className="text-[9px] opacity-75 leading-tight">
                            {formatTime(event.start_time)} - {formatTime(event.end_time)}
                          </div>
                        )}
                        {canDeleteEvent(event) && (
                          <button
                            onClick={(e) => {
                              e.stopPropagation();
                              deleteEvent.mutate(event.event_id);
                            }}
                            className="absolute -top-1 -right-1 w-5 h-5 bg-destructive text-destructive-foreground rounded-full opacity-0 group-hover:opacity-100 transition-all text-sm flex items-center justify-center hover:scale-110 shadow-sm"
                            title="Supprimer l'événement"
                          >
                            ×
                          </button>
                        )}
                      </div>
                    );
                  })}
              </div>
            ))}
          </div>
        ))}
      </div>
    </div>
  );

  const renderDayView = () => (
    <div className="flex-1 bg-card border border-border flex flex-col">
      {/* Day header */}
      <div className="p-4 border-b border-border text-center">
        <div className="text-sm text-muted-foreground uppercase">
          {dayNames[currentDate.getDay()]}
        </div>
        <div className="text-2xl font-medium text-foreground mt-1">{currentDate.getDate()}</div>
      </div>

      {/* Time slots */}
      <div className="flex-1 overflow-y-auto">
        {timeSlots.map((time) => (
          <div
            key={time}
            className="flex border-b border-border hover:bg-muted cursor-pointer relative min-h-[60px]"
            onClick={() => {
              const [hour] = time.split(":").map(Number);
              const dateWithTime = new Date(currentDate);
              dateWithTime.setHours(hour, 0, 0, 0);
              navigateToCreateEvent(dateWithTime, selectedTabloId);
            }}
          >
            <div className="w-20 p-2 text-xs text-muted-foreground text-right border-r border-border">
              {time}
            </div>
            <div className="flex-1 p-2 relative">
              {/* Current time indicator for today */}
              {isWithinCurrentHour(new Date(currentDate), time) && (
                <div
                  className="absolute left-0 right-0 h-0.5 bg-destructive z-20 pointer-events-none"
                  style={{
                    top: `${getCurrentTimePosition()}px`,
                  }}
                >
                  <div className="absolute -left-1 -top-1 w-2 h-2 bg-destructive rounded-full"></div>
                </div>
              )}

              {getEventsForDate(currentDate)
                .filter((event) => event.start_time.startsWith(time.split(":")[0]))
                .map((event) => {
                  const eventHeight = calculateEventHeight(event.start_time, event.end_time);
                  const eventOffset = calculateEventOffset(event.start_time, time);
                  return (
                    <div
                      key={event.event_id}
                      className={`absolute left-2 right-2 p-1 rounded text-white ${
                        event.tablo_color
                      } overflow-hidden z-10 group ${
                        canEditEvent(event)
                          ? "cursor-pointer hover:opacity-90"
                          : "cursor-default opacity-75"
                      }`}
                      style={{
                        top: `${eventOffset}px`,
                        height: `${eventHeight}px`,
                        minHeight: "30px",
                      }}
                      title={`${formatTime(event.start_time)} - ${formatTime(
                        event.end_time
                      )} ${event.title}${
                        selectedTabloId === "all" && event.tablo_name
                          ? ` - ${event.tablo_name}`
                          : ""
                      }${!canEditEvent(event) ? " (Lecture seule)" : ""}`}
                      onClick={(e) => {
                        e.stopPropagation();
                        if (canEditEvent(event)) {
                          navigate(`/planning/${event.tablo_id}/events/${event.event_id}/edit`);
                        }
                      }}
                    >
                      <div className="text-[10px] font-medium truncate leading-tight">
                        {event.title}
                        {selectedTabloId === "all" && event.tablo_name && (
                          <span className="opacity-75 ml-1">• {event.tablo_name}</span>
                        )}
                      </div>
                      {eventHeight >= 30 && (
                        <div className="text-[9px] opacity-75 leading-tight">
                          {formatTime(event.start_time)} - {formatTime(event.end_time)}
                        </div>
                      )}
                      {eventHeight >= 75 && event.description && (
                        <div className="text-[8px] mt-0.5 opacity-75 leading-tight">
                          {event.description}
                        </div>
                      )}
                      {canDeleteEvent(event) && (
                        <button
                          onClick={(e) => {
                            e.stopPropagation();
                            deleteEvent.mutate(event.event_id);
                          }}
                          className="absolute -top-1 -right-1 w-5 h-5 bg-destructive text-destructive-foreground rounded-full opacity-0 group-hover:opacity-100 transition-all text-sm flex items-center justify-center hover:scale-110 shadow-sm"
                          title="Supprimer l'événement"
                        >
                          ×
                        </button>
                      )}
                    </div>
                  );
                })}
            </div>
          </div>
        ))}
      </div>
    </div>
  );

  // ── Events card view ──────────────────────────────────────────────────────
  const renderEventsView = () => {
    const today = new Date();
    today.setHours(0, 0, 0, 0);
    const filtered = tabloEvents.filter((e) => {
      if (showAllEvents) return true;
      const eventDate = e.start_date ? new Date(`${e.start_date}T00:00:00`) : null;
      return !eventDate || eventDate >= today;
    });

    const months = [
      "JAN",
      "FÉV",
      "MAR",
      "AVR",
      "MAI",
      "JUN",
      "JUL",
      "AOÛ",
      "SEP",
      "OCT",
      "NOV",
      "DÉC",
    ];

    return (
      <div className="py-6 px-2">
        {/* Header */}
        <div className="flex items-center justify-between mb-6 flex-wrap gap-4">
          <h1 className="text-2xl font-bold text-gray-900 dark:text-gray-100">
            {t("planning:events", "Événements")}
          </h1>
          <button
            type="button"
            onClick={() => {
              if (!isReadOnly) setIsCreateEventOpen(true);
            }}
            disabled={isReadOnly}
            className="flex items-center gap-2 px-5 py-3 bg-[#804EEC] hover:bg-[#6f3fd4] text-white rounded-xl transition-colors font-medium shadow-sm disabled:opacity-50"
          >
            <PlusIcon className="w-5 h-5" />
            <span>{t("planning:createEvent")}</span>
          </button>
        </div>

        {/* Filter toggle */}
        <div className="flex items-center gap-2 mb-8">
          <button
            type="button"
            onClick={() => setShowAllEvents(false)}
            className={`px-4 py-2 rounded-lg text-sm font-medium transition-colors border ${
              !showAllEvents
                ? "bg-[#804EEC] text-white border-[#804EEC]"
                : "bg-white dark:bg-gray-800 text-gray-700 dark:text-gray-300 border-gray-200 dark:border-gray-700 hover:bg-gray-50 dark:hover:bg-gray-700"
            }`}
          >
            À venir
          </button>
          <button
            type="button"
            onClick={() => setShowAllEvents(true)}
            className={`px-4 py-2 rounded-lg text-sm font-medium transition-colors border ${
              showAllEvents
                ? "bg-[#804EEC] text-white border-[#804EEC]"
                : "bg-white dark:bg-gray-800 text-gray-700 dark:text-gray-300 border-gray-200 dark:border-gray-700 hover:bg-gray-50 dark:hover:bg-gray-700"
            }`}
          >
            Tous les événements
          </button>
        </div>

        {/* Event cards grid */}
        {tabloEventsLoading ? (
          <div className="flex items-center justify-center py-24">
            <img
              src="/icon.jpg"
              alt="Loading..."
              className="animate-spin rounded-full h-8 w-8 object-cover"
            />
          </div>
        ) : filtered.length === 0 ? (
          <div className="flex flex-col items-center justify-center py-24 text-center">
            <p className="text-gray-500 dark:text-gray-400 text-lg font-medium">
              Aucun événement trouvé
            </p>
            <p className="text-gray-400 dark:text-gray-500 text-sm mt-1">
              {showAllEvents ? "Aucun événement trouvé" : "Aucun événement à venir"}
            </p>
          </div>
        ) : (
          <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-5">
            {filtered.map((event) => {
              const date = event.start_date ? new Date(`${event.start_date}T00:00:00`) : null;
              const monthLabel = date ? months[date.getMonth()] : "";
              const dayLabel = date ? String(date.getDate()).padStart(2, "0") : "";
              const TabloIcon = getTabloIcon(event.tablo_color);
              const iconColor = getTabloIconColor(event.tablo_color);
              const timeLabel = event.start_time
                ? `${event.start_time.slice(0, 5)}${event.end_time ? ` – ${event.end_time.slice(0, 5)}` : ""}`
                : null;

              return (
                <div
                  key={event.event_id}
                  className="bg-white dark:bg-gray-800 rounded-2xl p-6 border border-gray-200 dark:border-gray-700 hover:shadow-lg transition-all hover:border-gray-300 dark:hover:border-gray-600 relative group"
                >
                  <DropdownMenu>
                    <DropdownMenuTrigger asChild>
                      <button
                        type="button"
                        className="absolute top-6 right-6 p-1 text-gray-400 hover:text-gray-600 dark:hover:text-gray-200 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg transition-colors opacity-0 group-hover:opacity-100"
                        aria-label="Options de l'événement"
                      >
                        <EllipsisVerticalIcon className="w-5 h-5" />
                      </button>
                    </DropdownMenuTrigger>
                    <DropdownMenuContent align="end" className="w-48">
                      <DropdownMenuItem
                        onClick={() => navigateToEditEvent(event)}
                        disabled={!canEditEvent(event) || isReadOnly}
                      >
                        Replanifier
                      </DropdownMenuItem>
                      <DropdownMenuSeparator />
                      <DropdownMenuItem
                        onClick={() => deleteEvent.mutate(event.event_id)}
                        disabled={!canDeleteEvent(event) || isReadOnly || deleteEvent.isPending}
                        className="text-destructive focus:text-destructive"
                      >
                        Supprimer
                      </DropdownMenuItem>
                    </DropdownMenuContent>
                  </DropdownMenu>

                  <div className="flex items-start gap-4 mb-4">
                    {/* Date badge */}
                    <div className="flex-shrink-0">
                      <div className="w-14 h-14 rounded-[8px] bg-[#F4F3FF] dark:bg-purple-900/20 flex flex-col items-center justify-center">
                        <span className="text-[10px] font-semibold text-[#7F56D9] dark:text-purple-400 uppercase tracking-wide leading-none">
                          {monthLabel}
                        </span>
                        <span className="text-xl font-bold text-[#7F56D9] dark:text-purple-400 leading-none mt-0.5">
                          {dayLabel}
                        </span>
                      </div>
                    </div>

                    {/* Title + description */}
                    <div className="flex-1 min-w-0 pt-1 pr-8">
                      <h3 className="text-lg font-semibold text-gray-900 dark:text-gray-100 mb-1 leading-tight">
                        {event.title}
                      </h3>
                      {event.description && (
                        <p className="text-sm text-gray-500 dark:text-gray-400 line-clamp-2">
                          {event.description}
                        </p>
                      )}
                    </div>
                  </div>

                  {/* Meta */}
                  <div className="space-y-2.5 mt-3">
                    {timeLabel && (
                      <div className="flex items-center gap-2.5 text-[#344054] dark:text-gray-300">
                        <ClockIcon className="w-4 h-4 flex-shrink-0" />
                        <span className="text-sm">{timeLabel}</span>
                      </div>
                    )}
                    {event.tablo_name && (
                      <div className="flex items-center gap-2.5 text-[#344054] dark:text-gray-300">
                        <div
                          className={`w-5 h-5 rounded-[5px] flex-shrink-0 flex items-center justify-center ${event.tablo_color || "bg-gray-400"}`}
                        >
                          <TabloIcon className={`w-3 h-3 ${iconColor}`} />
                        </div>
                        <span className="text-sm truncate">{event.tablo_name}</span>
                      </div>
                    )}
                  </div>
                </div>
              );
            })}
          </div>
        )}
      </div>
    );
  };

  if (currentTab === "events") {
    return (
      <div className="min-h-screen bg-background px-4">
        {renderEventsView()}
        <EventModal
          mode="create"
          isOpen={isCreateEventOpen}
          onClose={() => setIsCreateEventOpen(false)}
          defaultTabloId={selectedTabloId !== "all" ? selectedTabloId : undefined}
          defaultDate={currentDate}
        />
        <Outlet />
      </div>
    );
  }

  return (
    <div className="min-h-screen bg-background">
      <div className="flex">
        {/* Sidebar */}
        <div className="w-64 bg-card border-r border-border min-h-screen">
          <div className="p-4">
            {/* Tablo Selector */}
            <div className="mb-4">
              <Select
                value={selectedTabloId}
                onValueChange={(value) => setSelectedTabloId(value)}
                disabled={tablosLoading}
              >
                <SelectTrigger className="w-full" aria-label={t("planning:selectTablo")}>
                  <SelectValue
                    placeholder={
                      tablosLoading ? t("common:actions.loading") : t("planning:selectTablo")
                    }
                  />
                </SelectTrigger>
                <SelectContent>
                  <SelectItem value="all">{t("planning:allTablos")}</SelectItem>
                  {tablos?.map((tablo) => (
                    <SelectItem key={tablo.id} value={tablo.id}>
                      {tablo.name}
                    </SelectItem>
                  ))}
                </SelectContent>
              </Select>
            </div>

            <Button
              onClick={() => {
                if (isReadOnly) {
                  toast.add(
                    {
                      title: t("common:error"),
                      description:
                        "Vous êtes en mode lecture seule. Vous ne pouvez pas créer d'événement.",
                      type: "error",
                    },
                    { timeout: 5000 }
                  );
                  return;
                }
                if (selectedTabloId === "all") {
                  navigate(`/planning/create?date=${currentDate.toISOString()}`);
                } else {
                  navigate(
                    `/planning/create?tablo_id=${selectedTabloId}&date=${currentDate.toISOString()}`
                  );
                }
              }}
              className="w-full bg-[#804EEC] hover:bg-[#6f3fd4] text-white"
              disabled={isReadOnly}
            >
              <PlusIcon className="w-5 h-5 mr-2" />
              {t("planning:createEvent")}
            </Button>

            <Button
              onClick={() => {
                if (isReadOnly) {
                  toast.add(
                    {
                      title: t("common:error"),
                      description:
                        "Vous êtes en mode lecture seule. Vous ne pouvez pas importer de calendrier.",
                      type: "error",
                    },
                    { timeout: 5000 }
                  );
                  return;
                }
                setIsImportModalOpen(true);
              }}
              variant="secondary"
              className="w-full mt-2"
              disabled={isReadOnly}
            >
              <FolderInputIcon className="w-5 h-5 mr-2" />
              {t("planning:importPlanning")}
            </Button>

            <Button
              onClick={handleExportICS}
              disabled={!tabloEvents || tabloEvents.length === 0}
              variant="outline"
              className="w-full mt-2"
              title={t("planning:exportICS")}
            >
              <Download className="w-4 h-4 mr-2" />
              {t("planning:export")}
            </Button>
          </div>

          {/* Mini Calendar */}
          <div className="p-4 border-t border-border">
            <div className="text-sm font-medium text-foreground mb-3">
              {monthNames[currentDate.getMonth()]} {currentDate.getFullYear()}
            </div>
            <div className="grid grid-cols-7 gap-1 text-xs">
              {dayNamesShort.map((day) => (
                <div key={day} className="text-center text-muted-foreground p-1">
                  {day.slice(0, 1)}
                </div>
              ))}
              {getDaysInMonth(currentDate).map((day, index) => (
                <div
                  key={index}
                  className={`text-center p-1 cursor-pointer rounded ${
                    day ? "hover:bg-muted" : ""
                  } ${
                    day && formatDate(day) === formatDate(new Date())
                      ? "bg-[#804EEC] text-white"
                      : day
                        ? "text-foreground"
                        : ""
                  }`}
                  onClick={() => {
                    if (day) {
                      navigateToCreateEvent(day, selectedTabloId);
                    }
                  }}
                >
                  {day ? day.getDate() : ""}
                </div>
              ))}
            </div>
          </div>
        </div>

        {/* Main Content */}
        <div className="flex-1 flex flex-col">
          {/* Header */}
          <div className="bg-card border-b border-border p-4">
            <div className="flex items-center justify-between">
              <div className="flex items-center space-x-4">
                <TypographyH3>{t("planning:title")}</TypographyH3>
                <Button
                  onClick={goToToday}
                  variant="outline"
                  size="sm"
                  className="border-[#804EEC] text-[#804EEC] hover:bg-[#804EEC]/10"
                >
                  {t("planning:today")}
                </Button>
                <div className="flex items-center space-x-2">
                  <button onClick={() => navigateDate(-1)} className="p-2 hover:bg-muted rounded">
                    <svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                      <path
                        strokeLinecap="round"
                        strokeLinejoin="round"
                        strokeWidth="2"
                        d="M15 19l-7-7 7-7"
                      />
                    </svg>
                  </button>
                  <button onClick={() => navigateDate(1)} className="p-2 hover:bg-muted rounded">
                    <svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                      <path
                        strokeLinecap="round"
                        strokeLinejoin="round"
                        strokeWidth="2"
                        d="M9 5l7 7-7 7"
                      />
                    </svg>
                  </button>
                </div>
                <TypographyH4>{getViewTitle()}</TypographyH4>
              </div>

              <div className="flex items-center space-x-2">
                <Button
                  onClick={() => setIsWebcalModalOpen(true)}
                  variant="outline"
                  size="sm"
                  title={t("planning:syncCalendar")}
                >
                  <RefreshCcw className="w-4 h-4 mr-1" />
                  {t("planning:sync")}
                </Button>
                <div className="flex bg-muted rounded-lg p-1">
                  {(["month", "week", "day"] as ViewType[]).map((view) => (
                    <button
                      key={view}
                      onClick={() => changeView(view)}
                      title={t(`planning:views.${view}Title`)}
                      className={`px-3 py-1.5 text-sm rounded-md transition-colors capitalize ${
                        currentView === view
                          ? "bg-white dark:bg-gray-800 text-[#804EEC] shadow-sm font-semibold"
                          : "text-muted-foreground hover:text-foreground"
                      }`}
                    >
                      {t(`planning:views.${view}`)}
                      <span className="ml-1 text-xs opacity-60">
                        {t(`planning:views.${view}Short`)}
                      </span>
                    </button>
                  ))}
                </div>
              </div>
            </div>
          </div>

          {/* Calendar Views */}
          <div className="flex-1 p-4">
            {tabloEventsLoading ? (
              <div className="flex items-center justify-center h-64">
                <img
                  src="/icon.jpg"
                  alt="Loading..."
                  className="animate-spin rounded-full h-8 w-8 object-cover"
                />
                <span className="ml-2 text-muted-foreground">{t("planning:loadingEvents")}</span>
              </div>
            ) : (
              <>
                {currentView === "month" && renderMonthView()}
                {currentView === "week" && renderWeekView()}
                {currentView === "day" && renderDayView()}
              </>
            )}
          </div>
        </div>
      </div>

      <Outlet />

      {isImportModalOpen && <ImportICSModal onClose={() => setIsImportModalOpen(false)} />}

      <WebcalModal open={isWebcalModalOpen} onOpenChange={setIsWebcalModalOpen} />
    </div>
  );
};
