import { LoadingSpinner } from "@ui/components/LoadingSpinner";
import { cn, toast } from "@xtablo/shared";
import type { UserTablo } from "@xtablo/shared/types/tablos.types";
import type { Etape, KanbanTask } from "@xtablo/shared-types";
import { Avatar, AvatarFallback, AvatarImage } from "@xtablo/ui/components/avatar";
import { Button } from "@xtablo/ui/components/button";
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogHeader,
  DialogTitle,
} from "@xtablo/ui/components/dialog";
import { Input } from "@xtablo/ui/components/input";
import {
  CalendarIcon,
  ChevronDownIcon,
  ChevronRightIcon,
  CircleCheckIcon,
  Compass,
  EllipsisVerticalIcon,
  FileTextIcon,
  Flame,
  FolderIcon,
  Gem,
  Heart,
  KanbanIcon,
  LayoutDashboardIcon,
  Leaf,
  ListChecksIcon,
  MapIcon,
  MessageCircleIcon,
  PlusIcon,
  Sparkles,
  Star,
  Sun,
  UserPlusIcon,
  Waves,
  Zap,
} from "lucide-react";
import { useEffect, useState } from "react";
import { Link, useNavigate, useParams, useSearchParams } from "react-router-dom";
import { GanttChart } from "../components/gantt/GanttChart";
import { TaskModal } from "../components/kanban/TaskModal";
import { TabloDiscussionSection } from "../components/TabloDiscussionSection";
import { TabloEventsSection } from "../components/TabloEventsSection";
import { TabloFilesSection } from "../components/TabloFilesSection";
import { TabloTasksSection } from "../components/TabloTasksSection";
import { useTabloDiscussionUnread } from "../hooks/channel";
import { useInviteUser } from "../hooks/invite";
import { useTabloFileNames } from "../hooks/tablo_data";
import { useCancelTabloInvite, usePendingTabloInvitesByTablo } from "../hooks/tablo_invites";
import {
  useTabloMembers,
  useTabloOverviewLayout,
  useTablosList,
  useUpdateTablo,
} from "../hooks/tablos";
import {
  useAllTasks,
  useCreateEtape,
  useCreateTask,
  useTabloEtapes,
  useUpdateTask,
} from "../hooks/tasks";
import { useUser } from "../providers/UserStoreProvider";
import { getEtapeProgressStats } from "../utils/etapeProgress";
import {
  DEFAULT_OVERVIEW_LAYOUT,
  type OverviewBlockId,
  type OverviewLayoutV1,
  sanitizeOverviewLayout,
} from "./tablo-details/overviewLayout";
import { moveBetweenZones, moveWithinZone } from "./tablo-details/overviewReorder";

// ─── Icon helpers ─────────────────────────────────────────────────────────────

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";
  }
}

// ─── Status helpers ───────────────────────────────────────────────────────────

function getStatusConfig(status: string) {
  switch (status) {
    case "in_progress":
      return {
        label: "En cours",
        badgeClass:
          "bg-yellow-50 text-yellow-700 border border-yellow-200 dark:bg-yellow-950/30 dark:text-yellow-400 dark:border-yellow-800",
      };
    case "done":
      return {
        label: "Terminé",
        badgeClass:
          "bg-green-50 text-green-600 border border-green-200 dark:bg-green-950/30 dark:text-green-400 dark:border-green-800",
      };
    default:
      return {
        label: "À faire",
        badgeClass:
          "bg-blue-50 text-blue-600 border border-blue-200 dark:bg-blue-950/30 dark:text-blue-400 dark:border-blue-800",
      };
  }
}

// ─── Tabs ─────────────────────────────────────────────────────────────────────

type TabSection =
  | "overview"
  | "board"
  | "list"
  | "roadmap"
  | "calendar"
  | "files"
  | "discussion"
  | "events"
  | "tasks"
  | "etapes";

const TABS: {
  id: TabSection;
  label: string;
  icon: React.ElementType;
  disabled?: boolean;
}[] = [
  { id: "overview", label: "Aperçu", icon: LayoutDashboardIcon },
  { id: "etapes", label: "Étapes", icon: ListChecksIcon },
  { id: "tasks", label: "Tâches", icon: KanbanIcon },
  { id: "files", label: "Fichiers", icon: FolderIcon },
  { id: "discussion", label: "Discussion", icon: MessageCircleIcon },
  { id: "events", label: "Événements", icon: CalendarIcon },
  { id: "roadmap", label: "Roadmap", icon: MapIcon },
];

// ─── Page ─────────────────────────────────────────────────────────────────────

export const TabloDetailsPage = () => {
  const { tabloId } = useParams<{ tabloId: string }>();
  const navigate = useNavigate();
  const [searchParams, setSearchParams] = useSearchParams();
  const { data: tablos, isLoading } = useTablosList();
  const { hasUnread: hasUnreadDiscussion } = useTabloDiscussionUnread(tabloId);

  const [isTaskModalOpen, setIsTaskModalOpen] = useState(false);
  const [taskModalInitialDueDate, setTaskModalInitialDueDate] = useState<Date | undefined>(
    undefined
  );
  const [showAllOverviewTasks, setShowAllOverviewTasks] = useState(false);
  const [isShareDialogOpen, setIsShareDialogOpen] = useState(false);
  const [inviteEmail, setInviteEmail] = useState("");
  const [isLayoutEditMode, setIsLayoutEditMode] = useState(false);
  const [draggedOverviewBlock, setDraggedOverviewBlock] = useState<{
    zone: "left" | "right";
    index: number;
  } | null>(null);
  const [overviewLayout, setOverviewLayout] = useState<OverviewLayoutV1>(DEFAULT_OVERVIEW_LAYOUT);

  const currentUser = useUser();
  const { data: members } = useTabloMembers(tabloId ?? "");
  const { data: rawOverviewLayout } = useTabloOverviewLayout(tabloId);
  const { data: pendingInvites } = usePendingTabloInvitesByTablo(tabloId ?? "");
  const { mutate: cancelInvite, isPending: isCancellingInvite } = useCancelTabloInvite();
  const { mutate: inviteUser, isPending: isInvitingUser } = useInviteUser();
  const { mutate: updateTask } = useUpdateTask();
  const { mutate: updateTablo } = useUpdateTablo();

  const isEmailValid = (email: string): boolean => {
    const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    return emailRegex.test(email);
  };

  const handleSendInvite = () => {
    if (inviteEmail.trim() && tabloId) {
      inviteUser({ email: inviteEmail, tablo_id: tabloId });
      setInviteEmail("");
    }
  };

  const filteredMembers = members?.filter(
    (member) => !pendingInvites?.some((invite) => invite.invited_email === member.email)
  );

  const openTaskModal = (dueDate?: Date) => {
    setTaskModalInitialDueDate(dueDate ? new Date(dueDate) : undefined);
    setIsTaskModalOpen(true);
  };

  const closeTaskModal = () => {
    setIsTaskModalOpen(false);
    setTaskModalInitialDueDate(undefined);
  };

  const sectionParam = searchParams.get("section") as TabSection | null;
  const activeSection: TabSection =
    sectionParam && TABS.some((t) => t.id === sectionParam && !t.disabled)
      ? sectionParam
      : "overview";

  const [tablo, setTablo] = useState<UserTablo | null>(null);

  useEffect(() => {
    if (tablos && tabloId) {
      const found = tablos.find((t) => t.id === tabloId);
      if (found) {
        setTablo(found);
      } else {
        toast.add(
          {
            title: "Projet introuvable",
            description: "Le projet demandé n'existe pas ou vous n'y avez pas accès",
            type: "error",
          },
          { timeout: 5000 }
        );
        navigate("/tablos");
      }
    }
  }, [tablos, tabloId, navigate]);

  useEffect(() => {
    setOverviewLayout(sanitizeOverviewLayout(rawOverviewLayout));
  }, [rawOverviewLayout]);

  // Tasks for this tablo (used in overview)
  const { data: allTasks = [] } = useAllTasks();
  const tabloTasks = (allTasks as KanbanTask[]).filter((t) => t.tablo_id === tabloId);
  const myTabloTasks = tabloTasks.filter((task) => task.assignee_id === currentUser.id);
  const visibleOverviewTasks = showAllOverviewTasks ? myTabloTasks : myTabloTasks.slice(0, 5);

  // Etapes (parent tasks) for this tablo
  const { data: etapes = [] } = useTabloEtapes(tabloId);

  // Files for this tablo (used in overview)
  const { data: filesData } = useTabloFileNames(tabloId ?? "");
  const fileNames = (filesData?.fileNames ?? []).filter((f) => !f.startsWith("."));

  if (isLoading) {
    return (
      <div className="flex items-center justify-center h-64">
        <LoadingSpinner />
      </div>
    );
  }

  if (!tablo) return null;

  const { label: statusLabel, badgeClass } = getStatusConfig(tablo.status);
  const progress = getEtapeProgressStats(etapes);
  const isAdmin = tablo.is_admin;
  const TabloIcon = getTabloIcon(tablo.color);
  const iconColor = getTabloIconColor(tablo.color);

  const persistOverviewLayout = (
    nextLayout: OverviewLayoutV1,
    previousLayout: OverviewLayoutV1
  ) => {
    setOverviewLayout(nextLayout);

    if (!tabloId) return;

    updateTablo(
      {
        id: tabloId,
        layout_overview_v1: nextLayout,
      },
      {
        onError: () => {
          setOverviewLayout(previousLayout);
        },
      }
    );
  };

  const buildLayoutWithMetadata = (next: OverviewLayoutV1): OverviewLayoutV1 => ({
    ...next,
    updatedAt: new Date().toISOString(),
    updatedBy: currentUser.id,
  });

  const handleOverviewBlockDragStart = (
    event: React.DragEvent<HTMLDivElement>,
    zone: "left" | "right",
    index: number
  ) => {
    if (!isLayoutEditMode) return;
    event.dataTransfer.effectAllowed = "move";
    setDraggedOverviewBlock({ zone, index });
  };

  const handleOverviewBlockDragOver = (event: React.DragEvent<HTMLDivElement>) => {
    if (!isLayoutEditMode) return;
    event.preventDefault();
    event.dataTransfer.dropEffect = "move";
  };

  const handleOverviewBlockDrop = (zone: "left" | "right", targetIndex: number) => {
    if (!isLayoutEditMode || !draggedOverviewBlock) {
      setDraggedOverviewBlock(null);
      return;
    }

    const sourceKey = draggedOverviewBlock.zone === "left" ? "leftZone" : "rightZone";
    const targetKey = zone === "left" ? "leftZone" : "rightZone";

    const sourceZone = overviewLayout[sourceKey];
    const targetZone = overviewLayout[targetKey];

    const nextLayout =
      sourceKey === targetKey
        ? {
            ...overviewLayout,
            [targetKey]: moveWithinZone(targetZone, draggedOverviewBlock.index, targetIndex),
          }
        : (() => {
            const moved = moveBetweenZones(
              sourceZone,
              targetZone,
              draggedOverviewBlock.index,
              targetIndex
            );
            return {
              ...overviewLayout,
              [sourceKey]: moved.sourceItems,
              [targetKey]: moved.targetItems,
            };
          })();

    setDraggedOverviewBlock(null);

    if (
      nextLayout.leftZone === overviewLayout.leftZone &&
      nextLayout.rightZone === overviewLayout.rightZone
    ) {
      return;
    }

    const previousLayout = overviewLayout;
    persistOverviewLayout(buildLayoutWithMetadata(nextLayout), previousLayout);
  };

  const handleResetOverviewLayout = () => {
    const previousLayout = overviewLayout;
    const resetLayout = buildLayoutWithMetadata(DEFAULT_OVERVIEW_LAYOUT);
    persistOverviewLayout(resetLayout, previousLayout);
  };

  return (
    <div>
      {/* ── Header ──────────────────────────────────────────────────────── */}
      <div className="px-4 pt-4">
        <div className="flex flex-col md:flex-row items-start justify-between mb-6 border-b border-[#F2F4F7] dark:border-gray-700 pb-5 gap-5 md:gap-0">
          <div className="flex items-center gap-4">
            <div
              className={cn(
                "w-12 h-12 rounded-lg flex items-center justify-center shrink-0 overflow-hidden",
                !tablo.image && (tablo.color || "bg-gray-400")
              )}
            >
              {tablo.image ? (
                <img src={tablo.image} alt={tablo.name} className="w-full h-full object-cover" />
              ) : (
                <TabloIcon className={cn("w-6 h-6", iconColor)} />
              )}
            </div>
            <h1 className="text-xl md:text-3xl font-bold text-foreground">{tablo.name}</h1>
          </div>

          <div className="flex flex-wrap items-center gap-3">
            <Link
              to={`/chat/${tabloId}`}
              className="bg-[#804EEC] hover:bg-[#6f3fd4] text-white font-medium py-2 px-4 rounded-lg flex items-center gap-2 transition-colors"
            >
              <MessageCircleIcon className="w-5 h-5" />
              Discussion
            </Link>
            {isAdmin && (
              <button
                type="button"
                onClick={() => setIsShareDialogOpen(true)}
                className="border border-[#804EEC] text-[#804EEC] hover:bg-[#804EEC]/10 font-medium py-2 px-4 rounded-lg flex items-center gap-2 transition-colors"
              >
                <UserPlusIcon className="w-5 h-5" />
                Inviter
              </button>
            )}
          </div>
        </div>

        {/* ── Metadata bar ──────────────────────────────────────────────── */}
        <div className="flex flex-wrap items-center gap-6 text-sm border-b border-[#F2F4F7] dark:border-gray-700 pb-4 mb-4">
          <div className="flex items-center gap-2 md:border-r border-[#D0D5DD] dark:border-gray-600 pr-4">
            <span className="text-muted-foreground">Rôle :</span>
            <span className="text-foreground font-medium">{isAdmin ? "Admin" : "Invité"}</span>
          </div>
          <div className="flex items-center gap-2 md:border-r border-[#D0D5DD] dark:border-gray-600 pr-4">
            <span className="text-muted-foreground">Créé le :</span>
            <span className="text-foreground">
              {new Intl.DateTimeFormat("fr-FR", {
                year: "numeric",
                month: "short",
                day: "2-digit",
              }).format(new Date(tablo.created_at))}
            </span>
          </div>
          <div className="flex items-center gap-2 md:border-r border-[#D0D5DD] dark:border-gray-600 pr-4">
            <span className="text-muted-foreground">Statut :</span>
            <span className={cn("px-3 py-1 rounded-full text-xs font-medium", badgeClass)}>
              {statusLabel}
            </span>
          </div>
          <div className="flex items-center gap-2">
            <span className="text-muted-foreground">Progression :</span>
            <div className="relative w-24 h-2 bg-gray-200 dark:bg-gray-700 rounded-full overflow-hidden">
              <div
                className="absolute inset-y-0 left-0 bg-blue-500/40"
                style={{ width: `${progress.startedPercentage}%` }}
              />
              <div
                className="absolute inset-y-0 left-0 bg-green-500"
                style={{ width: `${progress.donePercentage}%` }}
              />
            </div>
            <span className="text-foreground font-medium">{progress.donePercentage}%</span>
          </div>
        </div>
      </div>

      {/* ── Tab navigation ──────────────────────────────────────────────── */}
      <div className="w-full bg-white dark:bg-background sticky top-0 z-40">
        <div className="px-4 py-2">
          <div className="flex flex-wrap items-center gap-6 mb-4 border-b border-[#F2F4F7] dark:border-gray-700">
            {TABS.map((tab) => {
              const isActive = activeSection === tab.id;
              return (
                <button
                  key={tab.id}
                  type="button"
                  disabled={tab.disabled}
                  onClick={() => !tab.disabled && setSearchParams({ section: tab.id })}
                  className={cn(
                    "flex items-center gap-2 pb-3 px-1 text-sm font-semibold transition-colors border-b-2",
                    isActive
                      ? "text-[#804EEC] border-[#804EEC]"
                      : "text-[#667085] border-transparent hover:text-gray-900 dark:hover:text-gray-100",
                    tab.disabled && "opacity-40 cursor-not-allowed"
                  )}
                >
                  <span className="relative inline-flex">
                    <tab.icon className="w-4 h-4" />
                    {tab.id === "discussion" && hasUnreadDiscussion && (
                      <span className="absolute -top-1 -right-1 w-2 h-2 rounded-full bg-red-500" />
                    )}
                  </span>
                  <span>{tab.label}</span>
                  {tab.disabled && (
                    <span className="text-[10px] font-medium px-1.5 py-0.5 rounded-full bg-gray-100 dark:bg-gray-700 text-gray-500 dark:text-gray-400 leading-none">
                      Bientôt
                    </span>
                  )}
                </button>
              );
            })}
          </div>
        </div>
      </div>

      {/* ── Tab content ─────────────────────────────────────────────────── */}
      <div className="px-4 sm:px-6 pt-6 pb-8">
        {activeSection === "overview" &&
          (() => {
            const overviewBlocks: Record<OverviewBlockId, React.ReactNode> = {
              description: (
                <div className="bg-white dark:bg-card rounded-xl border border-border p-6 sm:p-8 shadow-sm">
                  <h2 className="text-xl sm:text-2xl font-bold text-foreground mb-4">
                    Description du projet
                  </h2>
                  <p className="text-muted-foreground leading-relaxed text-sm sm:text-base">
                    Ce projet regroupe les tâches, fichiers et événements associés. Utilisez les
                    onglets ci-dessus pour naviguer entre les différentes sections.
                  </p>
                </div>
              ),
              myTasks: (
                <div className="bg-white dark:bg-card rounded-xl border border-gray-100 dark:border-gray-700 shadow-sm overflow-hidden">
                  <div className="flex flex-col sm:flex-row sm:items-center justify-between px-4 sm:px-6 py-4 border-b border-gray-200 dark:border-gray-700 gap-3">
                    <h2 className="text-xl sm:text-2xl font-semibold text-gray-900 dark:text-gray-100">
                      Mes tâches
                    </h2>
                    <button
                      type="button"
                      onClick={() => openTaskModal()}
                      className="flex items-center justify-center gap-2 px-3 sm:px-4 py-2 bg-[#804EEC] hover:bg-[#6f3fd4] text-white rounded-xl w-full sm:w-auto transition-colors"
                    >
                      <PlusIcon className="w-4 h-4" />
                      <span className="text-sm">Ajouter</span>
                    </button>
                  </div>
                  <div className="divide-y divide-gray-200 dark:divide-gray-700">
                    {myTabloTasks.length === 0 ? (
                      <div className="p-6 text-center text-muted-foreground text-sm">
                        Aucune tâche
                      </div>
                    ) : (
                      visibleOverviewTasks.map((task) => (
                        <div
                          key={task.id}
                          className="flex items-center gap-3 p-4 hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors cursor-pointer"
                          onClick={() => setSearchParams({ section: "tasks" })}
                        >
                          <button
                            type="button"
                            className="shrink-0"
                            onClick={(e) => {
                              e.stopPropagation();
                              if (task.status !== "done") {
                                updateTask({ id: task.id, status: "done" });
                              }
                            }}
                            aria-label={
                              task.status === "done"
                                ? "Tâche terminée"
                                : "Marquer la tâche comme terminée"
                            }
                          >
                            {task.status === "done" ? (
                              <CircleCheckIcon className="w-5 h-5 text-green-500" />
                            ) : (
                              <div className="w-5 h-5 rounded-full border-2 border-gray-300 dark:border-gray-600" />
                            )}
                          </button>
                          <p
                            className={cn(
                              "text-sm font-medium truncate",
                              task.status === "done"
                                ? "line-through text-gray-400"
                                : "text-gray-900 dark:text-gray-100"
                            )}
                          >
                            {task.title}
                          </p>
                        </div>
                      ))
                    )}
                    {myTabloTasks.length > 5 && (
                      <button
                        type="button"
                        onClick={() => setShowAllOverviewTasks((prev) => !prev)}
                        className="w-full p-3 text-sm text-[#804EEC] hover:underline text-center"
                      >
                        {showAllOverviewTasks
                          ? "Voir moins"
                          : `Voir les ${myTabloTasks.length - 5} tâches restantes`}
                      </button>
                    )}
                  </div>
                </div>
              ),
              files: (
                <div className="bg-white dark:bg-card rounded-xl border border-border p-5 sm:p-6 shadow-sm">
                  <div className="flex items-center justify-between mb-4">
                    <h3 className="text-lg font-bold text-foreground">Fichiers</h3>
                    <button
                      type="button"
                      onClick={() => setSearchParams({ section: "files" })}
                      className="text-sm text-[#804EEC] hover:underline"
                    >
                      Voir tout
                    </button>
                  </div>
                  <div className="space-y-3">
                    {fileNames.length === 0 ? (
                      <p className="text-sm text-muted-foreground">Aucun fichier</p>
                    ) : (
                      fileNames.slice(0, 5).map((fileName) => (
                        <div
                          key={fileName}
                          className="flex items-start gap-3 p-3 hover:bg-accent dark:hover:bg-gray-800 rounded-lg transition-colors"
                        >
                          <div className="w-10 h-10 bg-red-100 dark:bg-red-900/30 rounded-lg flex items-center justify-center shrink-0">
                            <FileTextIcon className="w-4 h-4 text-red-500" />
                          </div>
                          <div className="flex-1 min-w-0">
                            <p className="font-medium text-foreground text-sm truncate">
                              {fileName}
                            </p>
                          </div>
                          <button
                            type="button"
                            className="text-muted-foreground hover:text-foreground p-1 shrink-0"
                          >
                            <EllipsisVerticalIcon className="w-4 h-4" />
                          </button>
                        </div>
                      ))
                    )}
                  </div>
                </div>
              ),
              info: (
                <div className="bg-white dark:bg-card rounded-xl border border-border p-5 sm:p-6 shadow-sm">
                  <h3 className="text-lg font-bold text-foreground mb-4">Informations</h3>
                  <dl className="space-y-3 text-sm">
                    <div className="flex justify-between">
                      <dt className="text-muted-foreground">Tâches</dt>
                      <dd className="font-medium text-foreground">{tabloTasks.length}</dd>
                    </div>
                    <div className="flex justify-between">
                      <dt className="text-muted-foreground">Fichiers</dt>
                      <dd className="font-medium text-foreground">{fileNames.length}</dd>
                    </div>
                    <div className="flex justify-between">
                      <dt className="text-muted-foreground">Statut</dt>
                      <dd
                        className={cn("px-2 py-0.5 rounded-full text-xs font-medium", badgeClass)}
                      >
                        {statusLabel}
                      </dd>
                    </div>
                    <div className="flex justify-between">
                      <dt className="text-muted-foreground">Rôle</dt>
                      <dd className="font-medium text-foreground">
                        {isAdmin ? "Admin" : "Invité"}
                      </dd>
                    </div>
                  </dl>
                </div>
              ),
            };

            return (
              <>
                {isAdmin && (
                  <div className="flex flex-wrap items-center justify-end gap-2 mb-4">
                    {isLayoutEditMode && (
                      <button
                        type="button"
                        onClick={handleResetOverviewLayout}
                        className="border border-gray-300 dark:border-gray-700 text-foreground hover:bg-gray-100 dark:hover:bg-gray-800 font-medium py-2 px-4 rounded-lg transition-colors"
                      >
                        Réinitialiser
                      </button>
                    )}
                    <button
                      type="button"
                      onClick={() => setIsLayoutEditMode((prev) => !prev)}
                      className={cn(
                        "font-medium py-2 px-4 rounded-lg transition-colors",
                        isLayoutEditMode
                          ? "bg-gray-900 dark:bg-gray-100 text-white dark:text-gray-900"
                          : "border border-[#804EEC] text-[#804EEC] hover:bg-[#804EEC]/10"
                      )}
                    >
                      {isLayoutEditMode ? "Terminer la mise en page" : "Modifier la mise en page"}
                    </button>
                  </div>
                )}

                <div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
                  <div
                    className="lg:col-span-2 space-y-6"
                    onDragOver={handleOverviewBlockDragOver}
                    onDrop={(event) => {
                      event.preventDefault();
                      handleOverviewBlockDrop("left", overviewLayout.leftZone.length);
                    }}
                  >
                    {overviewLayout.leftZone.map((blockId, index) => (
                      <div
                        key={`${blockId}-${index}`}
                        draggable={isLayoutEditMode}
                        onDragStart={(event) => handleOverviewBlockDragStart(event, "left", index)}
                        onDragOver={handleOverviewBlockDragOver}
                        onDrop={(event) => {
                          event.preventDefault();
                          event.stopPropagation();
                          handleOverviewBlockDrop("left", index);
                        }}
                        onDragEnd={() => setDraggedOverviewBlock(null)}
                        className={cn(
                          isLayoutEditMode && "cursor-move",
                          isLayoutEditMode &&
                            draggedOverviewBlock?.zone === "left" &&
                            draggedOverviewBlock.index === index &&
                            "opacity-60"
                        )}
                      >
                        {isLayoutEditMode && (
                          <div className="flex items-center justify-end mb-2 text-xs text-muted-foreground">
                            <EllipsisVerticalIcon className="w-4 h-4 mr-1" />
                            Glisser pour réorganiser
                          </div>
                        )}
                        {overviewBlocks[blockId]}
                      </div>
                    ))}
                    {isLayoutEditMode && overviewLayout.leftZone.length === 0 && (
                      <div className="border border-dashed border-gray-300 dark:border-gray-700 rounded-xl p-4 text-sm text-muted-foreground text-center">
                        Déposez un bloc ici
                      </div>
                    )}
                  </div>

                  <div
                    className="space-y-6"
                    onDragOver={handleOverviewBlockDragOver}
                    onDrop={(event) => {
                      event.preventDefault();
                      handleOverviewBlockDrop("right", overviewLayout.rightZone.length);
                    }}
                  >
                    {overviewLayout.rightZone.map((blockId, index) => (
                      <div
                        key={`${blockId}-${index}`}
                        draggable={isLayoutEditMode}
                        onDragStart={(event) => handleOverviewBlockDragStart(event, "right", index)}
                        onDragOver={handleOverviewBlockDragOver}
                        onDrop={(event) => {
                          event.preventDefault();
                          event.stopPropagation();
                          handleOverviewBlockDrop("right", index);
                        }}
                        onDragEnd={() => setDraggedOverviewBlock(null)}
                        className={cn(
                          isLayoutEditMode && "cursor-move",
                          isLayoutEditMode &&
                            draggedOverviewBlock?.zone === "right" &&
                            draggedOverviewBlock.index === index &&
                            "opacity-60"
                        )}
                      >
                        {isLayoutEditMode && (
                          <div className="flex items-center justify-end mb-2 text-xs text-muted-foreground">
                            <EllipsisVerticalIcon className="w-4 h-4 mr-1" />
                            Glisser pour réorganiser
                          </div>
                        )}
                        {overviewBlocks[blockId]}
                      </div>
                    ))}
                    {isLayoutEditMode && overviewLayout.rightZone.length === 0 && (
                      <div className="border border-dashed border-gray-300 dark:border-gray-700 rounded-xl p-4 text-sm text-muted-foreground text-center">
                        Déposez un bloc ici
                      </div>
                    )}
                  </div>
                </div>
              </>
            );
          })()}

        {activeSection === "tasks" && <TabloTasksSection tablo={tablo} isAdmin={isAdmin} />}
        {activeSection === "files" && <TabloFilesSection tablo={tablo} isAdmin={isAdmin} />}
        {activeSection === "discussion" && (
          <TabloDiscussionSection tablo={tablo} isAdmin={isAdmin} />
        )}
        {activeSection === "events" && <TabloEventsSection tablo={tablo} isAdmin={isAdmin} />}

        {activeSection === "etapes" && (
          <EtapesSection
            etapes={etapes}
            tabloTasks={tabloTasks}
            tabloId={tabloId ?? ""}
            isAdmin={isAdmin}
          />
        )}

        {activeSection === "roadmap" && (
          <RoadmapSection etapes={etapes} tabloTasks={tabloTasks} onDateClick={openTaskModal} />
        )}
      </div>

      {/* Task Create Modal */}
      {tabloId && (
        <TaskModal
          tabloId={tabloId}
          isOpen={isTaskModalOpen}
          onClose={closeTaskModal}
          initialStatus="todo"
          initialDueDate={taskModalInitialDueDate}
        />
      )}

      {/* Share / Invite Dialog */}
      <Dialog open={isShareDialogOpen} onOpenChange={setIsShareDialogOpen}>
        <DialogContent className="max-w-md">
          <DialogHeader>
            <DialogTitle>Partager le projet</DialogTitle>
            <DialogDescription>Invitez des personnes à collaborer sur ce projet</DialogDescription>
          </DialogHeader>

          <div className="space-y-4">
            {/* Invite Input */}
            <div className="flex space-x-2">
              <Input
                type="email"
                value={inviteEmail}
                onChange={(e) => setInviteEmail(e.target.value)}
                placeholder="Email de l'utilisateur"
                className="flex-1"
              />
              {isInvitingUser ? (
                <div className="flex justify-center items-center px-4">
                  <div className="animate-spin rounded-full h-4 w-4 border-b-2 border-primary" />
                </div>
              ) : (
                <Button
                  type="button"
                  onClick={handleSendInvite}
                  disabled={!isEmailValid(inviteEmail)}
                >
                  Inviter
                </Button>
              )}
            </div>

            {/* Pending Invites */}
            {pendingInvites && pendingInvites.length > 0 && (
              <div>
                <h4 className="text-sm font-semibold text-foreground mb-2">
                  Invitations en attente ({pendingInvites.length})
                </h4>
                <div className="space-y-2 max-h-32 overflow-y-auto">
                  {pendingInvites.map((invite) => (
                    <div
                      key={invite.id}
                      className="flex items-center space-x-2 p-2 bg-orange-50 dark:bg-orange-950/20 rounded-lg border border-dashed border-orange-200 dark:border-orange-900/50"
                    >
                      <div className="w-8 h-8 bg-orange-100 dark:bg-orange-900/30 rounded-full flex items-center justify-center text-orange-600 dark:text-orange-400 text-xs">
                        <svg
                          className="w-4 h-4"
                          fill="none"
                          stroke="currentColor"
                          viewBox="0 0 24 24"
                        >
                          <path
                            strokeLinecap="round"
                            strokeLinejoin="round"
                            strokeWidth={2}
                            d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"
                          />
                        </svg>
                      </div>
                      <div className="flex-1 min-w-0">
                        <span className="text-xs font-medium text-foreground truncate block">
                          {invite.invited_email}
                        </span>
                      </div>
                      <Button
                        size="sm"
                        variant="ghost"
                        onClick={() =>
                          cancelInvite({
                            tabloId: tabloId ?? "",
                            inviteId: invite.id,
                          })
                        }
                        disabled={isCancellingInvite || !tabloId}
                        title="Retirer l'invitation"
                      >
                        {isCancellingInvite ? "..." : "Retirer"}
                      </Button>
                    </div>
                  ))}
                </div>
              </div>
            )}

            {/* Members List */}
            {filteredMembers && filteredMembers.length > 0 && (
              <div>
                <h4 className="text-sm font-semibold text-foreground mb-2">
                  Membres ({filteredMembers.length})
                </h4>
                <div className="space-y-2 max-h-48 overflow-y-auto">
                  {filteredMembers.map((member) => {
                    const avatarUrl =
                      member.avatar_url ??
                      (member.id === currentUser.id ? currentUser.avatar_url : null);
                    return (
                      <div
                        key={member.id}
                        className="flex items-center space-x-2 p-2 bg-muted rounded-lg"
                      >
                        <Avatar className="w-8 h-8">
                          {avatarUrl && <AvatarImage src={avatarUrl} alt={member.name} />}
                          <AvatarFallback className="bg-primary text-primary-foreground text-xs font-medium">
                            {member.name.charAt(0).toUpperCase()}
                          </AvatarFallback>
                        </Avatar>
                        <div className="flex-1 min-w-0">
                          <span className="text-xs font-medium text-foreground truncate block">
                            {member.name}
                          </span>
                          <span className="text-xs text-muted-foreground">
                            {member.is_admin ? "Admin" : "Invité"}
                          </span>
                        </div>
                      </div>
                    );
                  })}
                </div>
              </div>
            )}
          </div>
        </DialogContent>
      </Dialog>
    </div>
  );
};

// ─── Etapes (Steps) section ─────────────────────────────────────────────────

function EtapesSection({
  etapes,
  tabloTasks,
  tabloId,
  isAdmin,
}: {
  etapes: Etape[];
  tabloTasks: KanbanTask[];
  tabloId: string;
  isAdmin: boolean;
}) {
  const [expandedEtapes, setExpandedEtapes] = useState<Set<string>>(
    new Set(etapes.map((e) => e.id))
  );
  const [addingTaskToEtape, setAddingTaskToEtape] = useState<string | null>(null);
  const [newEtapeTitle, setNewEtapeTitle] = useState("");
  const [newTaskTitle, setNewTaskTitle] = useState("");
  const { mutate: createTask } = useCreateTask();
  const { mutateAsync: createEtape, isPending: isCreatingEtape } = useCreateEtape();

  const toggleEtape = (id: string) => {
    setExpandedEtapes((prev) => {
      const next = new Set(prev);
      if (next.has(id)) next.delete(id);
      else next.add(id);
      return next;
    });
  };

  const handleAddTask = (etapeId: string) => {
    const title = newTaskTitle.trim();
    if (!title || !tabloId) return;
    createTask({
      tablo_id: tabloId,
      title,
      status: "todo",
      parent_task_id: etapeId,
      is_parent: false,
      position: tabloTasks.filter((t) => t.parent_task_id === etapeId).length,
    });
    setNewTaskTitle("");
    setAddingTaskToEtape(null);
  };

  const handleAddEtape = async () => {
    const title = newEtapeTitle.trim();
    if (!title || !tabloId) {
      return;
    }

    const nextPosition = etapes.reduce((max, etape) => Math.max(max, etape.position), -1) + 1;

    await createEtape({
      tabloId,
      title,
      position: nextPosition,
    });

    setNewEtapeTitle("");
  };

  const statusConfig: Record<string, { label: string; color: string }> = {
    todo: {
      label: "À faire",
      color: "bg-blue-100 text-blue-700 dark:bg-blue-950/30 dark:text-blue-400",
    },
    in_progress: {
      label: "En cours",
      color: "bg-yellow-100 text-yellow-700 dark:bg-yellow-950/30 dark:text-yellow-400",
    },
    in_review: {
      label: "Vérification",
      color: "bg-purple-100 text-purple-700 dark:bg-purple-950/30 dark:text-purple-400",
    },
    done: {
      label: "Terminé",
      color: "bg-green-100 text-green-700 dark:bg-green-950/30 dark:text-green-400",
    },
  };

  return (
    <div className="space-y-4">
      {isAdmin && (
        <div className="flex items-center gap-2">
          <Input
            value={newEtapeTitle}
            onChange={(event) => setNewEtapeTitle(event.target.value)}
            placeholder="Nom de la nouvelle étape..."
            onKeyDown={(event) => {
              if (event.key === "Enter") {
                void handleAddEtape();
              }
            }}
            className="h-9 sm:w-80"
          />
          <Button
            onClick={() => void handleAddEtape()}
            disabled={isCreatingEtape || !newEtapeTitle.trim()}
          >
            <PlusIcon className="w-4 h-4" />
            Ajouter une étape
          </Button>
        </div>
      )}

      {etapes.length === 0 ? (
        <div className="flex flex-col items-center justify-center py-24 text-center">
          <ListChecksIcon className="w-12 h-12 text-gray-300 dark:text-gray-600 mb-4" />
          <p className="text-gray-500 dark:text-gray-400 text-lg font-medium">Aucune étape</p>
          <p className="text-gray-400 dark:text-gray-500 text-sm mt-1">
            Les étapes permettent de structurer votre projet en grandes phases
          </p>
        </div>
      ) : (
        etapes.map((etape, index) => {
          const childTasks = tabloTasks.filter((t) => t.parent_task_id === etape.id);
          const doneCount = childTasks.filter((t) => t.status === "done").length;
          const totalCount = childTasks.length;
          const progressPct = totalCount > 0 ? Math.round((doneCount / totalCount) * 100) : 0;
          const isExpanded = expandedEtapes.has(etape.id);

          // Derive status from child tasks instead of etape.status
          const derivedStatus =
            totalCount === 0
              ? "todo"
              : doneCount === totalCount
                ? "done"
                : doneCount > 0
                  ? "in_progress"
                  : "todo";
          const status = statusConfig[derivedStatus] ?? statusConfig.todo;

          return (
            <div
              key={etape.id}
              className="bg-white dark:bg-card rounded-xl border border-gray-100 dark:border-gray-700 shadow-sm overflow-hidden"
            >
              {/* Etape header */}
              <button
                type="button"
                onClick={() => toggleEtape(etape.id)}
                className="w-full flex items-center gap-4 px-5 py-4 hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors text-left"
              >
                {isExpanded ? (
                  <ChevronDownIcon className="w-5 h-5 text-gray-400 shrink-0" />
                ) : (
                  <ChevronRightIcon className="w-5 h-5 text-gray-400 shrink-0" />
                )}

                <div className="w-8 h-8 rounded-lg bg-[#F4F3FF] dark:bg-purple-900/20 flex items-center justify-center shrink-0">
                  <span className="text-sm font-bold text-[#7F56D9] dark:text-purple-400">
                    {index + 1}
                  </span>
                </div>

                <div className="flex-1 min-w-0">
                  <h3 className="font-semibold text-gray-900 dark:text-gray-100 truncate">
                    {etape.title}
                  </h3>
                  {etape.description && (
                    <p className="text-sm text-muted-foreground truncate mt-0.5">
                      {etape.description}
                    </p>
                  )}
                </div>

                {etape.due_date && (
                  <div
                    className={cn(
                      "flex items-center gap-1 text-xs shrink-0",
                      derivedStatus !== "done" &&
                        new Date(etape.due_date) < new Date(new Date().toDateString())
                        ? "text-red-500"
                        : "text-muted-foreground"
                    )}
                  >
                    <CalendarIcon className="w-3.5 h-3.5" />
                    <span>
                      {new Intl.DateTimeFormat("fr-FR", {
                        day: "2-digit",
                        month: "short",
                      }).format(new Date(etape.due_date))}
                    </span>
                  </div>
                )}

                <span
                  className={cn(
                    "px-2.5 py-1 rounded-full text-xs font-medium shrink-0",
                    status.color
                  )}
                >
                  {status.label}
                </span>

                {totalCount > 0 && (
                  <div className="flex items-center gap-2 shrink-0">
                    <div className="w-16 h-1.5 bg-gray-200 dark:bg-gray-700 rounded-full overflow-hidden">
                      <div
                        className="h-full bg-green-500 rounded-full transition-all"
                        style={{ width: `${progressPct}%` }}
                      />
                    </div>
                    <span className="text-xs text-muted-foreground whitespace-nowrap">
                      {doneCount}/{totalCount}
                    </span>
                  </div>
                )}
              </button>

              {/* Child tasks + add task */}
              {isExpanded && (
                <div className="border-t border-gray-100 dark:border-gray-700">
                  {childTasks.length > 0 && (
                    <div className="divide-y divide-gray-100 dark:divide-gray-700">
                      {childTasks.map((task) => (
                        <div
                          key={task.id}
                          className="flex items-center gap-3 px-5 py-3 pl-16 hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors"
                        >
                          {task.status === "done" ? (
                            <CircleCheckIcon className="w-4 h-4 text-green-500 shrink-0" />
                          ) : (
                            <div className="w-4 h-4 rounded-full border-2 border-gray-300 dark:border-gray-600 shrink-0" />
                          )}
                          <span
                            className={cn(
                              "text-sm flex-1 truncate",
                              task.status === "done"
                                ? "line-through text-gray-400"
                                : "text-gray-900 dark:text-gray-100"
                            )}
                          >
                            {task.title}
                          </span>
                          {task.due_date && (
                            <div
                              className={cn(
                                "flex items-center gap-1 text-xs shrink-0",
                                task.status !== "done" &&
                                  new Date(task.due_date) < new Date(new Date().toDateString())
                                  ? "text-red-500"
                                  : "text-muted-foreground"
                              )}
                            >
                              <CalendarIcon className="w-3 h-3" />
                              <span>
                                {new Intl.DateTimeFormat("fr-FR", {
                                  day: "2-digit",
                                  month: "short",
                                }).format(new Date(task.due_date))}
                              </span>
                            </div>
                          )}
                          {task.status && (
                            <span
                              className={cn(
                                "px-2 py-0.5 rounded-full text-[10px] font-medium shrink-0",
                                (statusConfig[task.status] ?? statusConfig.todo).color
                              )}
                            >
                              {(statusConfig[task.status] ?? statusConfig.todo).label}
                            </span>
                          )}
                        </div>
                      ))}
                    </div>
                  )}

                  {childTasks.length === 0 && addingTaskToEtape !== etape.id && (
                    <div className="px-5 py-4 pl-16 text-sm text-muted-foreground">
                      Aucune tâche dans cette étape
                    </div>
                  )}

                  {/* Inline add task */}
                  {addingTaskToEtape === etape.id ? (
                    <div className="flex items-center gap-2 px-5 py-3 pl-16 border-t border-gray-100 dark:border-gray-700">
                      <div className="w-4 h-4 rounded-full border-2 border-gray-300 dark:border-gray-600 shrink-0" />
                      <input
                        autoFocus
                        type="text"
                        value={newTaskTitle}
                        onChange={(e) => setNewTaskTitle(e.target.value)}
                        onKeyDown={(e) => {
                          if (e.key === "Enter") handleAddTask(etape.id);
                          if (e.key === "Escape") {
                            setAddingTaskToEtape(null);
                            setNewTaskTitle("");
                          }
                        }}
                        placeholder="Nom de la tâche..."
                        className="flex-1 text-sm bg-transparent border-none outline-none text-gray-900 dark:text-gray-100 placeholder-gray-400"
                      />
                      <button
                        type="button"
                        onClick={() => handleAddTask(etape.id)}
                        disabled={!newTaskTitle.trim()}
                        className="text-xs font-medium px-3 py-1 rounded-md bg-[#804EEC] text-white hover:bg-[#6f3fd4] disabled:opacity-40 transition-colors"
                      >
                        Ajouter
                      </button>
                      <button
                        type="button"
                        onClick={() => {
                          setAddingTaskToEtape(null);
                          setNewTaskTitle("");
                        }}
                        className="text-xs text-muted-foreground hover:text-foreground px-2 py-1"
                      >
                        Annuler
                      </button>
                    </div>
                  ) : (
                    <button
                      type="button"
                      onClick={(e) => {
                        e.stopPropagation();
                        setAddingTaskToEtape(etape.id);
                        setNewTaskTitle("");
                      }}
                      className="flex items-center gap-2 px-5 py-2.5 pl-16 text-sm text-muted-foreground hover:text-[#804EEC] hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors w-full text-left border-t border-gray-100 dark:border-gray-700"
                    >
                      <PlusIcon className="w-4 h-4" />
                      Ajouter une tâche
                    </button>
                  )}
                </div>
              )}
            </div>
          );
        })
      )}
    </div>
  );
}

// ─── Roadmap Section ─────────────────────────────────────────────────────────

function RoadmapSection({
  tabloTasks,
  onDateClick,
}: {
  etapes: Etape[];
  tabloTasks: KanbanTask[];
  onDateClick: (date: Date) => void;
}) {
  const { mutate: updateTask } = useUpdateTask();

  return (
    <GanttChart
      tasks={tabloTasks}
      isLoading={false}
      onDateClick={onDateClick}
      onTaskStatusChange={(taskId, status) => updateTask({ id: taskId, status })}
    />
  );
}
