import { LoadingSpinner } from "@ui/components/LoadingSpinner";
import { toast } from "@xtablo/shared";
import type { UserTablo } from "@xtablo/shared/types/tablos.types";
import type { KanbanTask } from "@xtablo/shared-types";
import {
  DEFAULT_OVERVIEW_LAYOUT,
  EtapesSection,
  getSingleTabloStatusConfig,
  moveBetweenZones,
  moveWithinZone,
  type OverviewLayoutV1,
  RoadmapSection,
  SingleTabloOverview,
  type SingleTabloTabId,
  SingleTabloView,
  sanitizeOverviewLayout,
  TabloDiscussionSection,
  TabloEventsSection,
  TabloFilesSection,
  TabloTasksSection,
  TaskModal,
  useChatUnread,
} from "@xtablo/tablo-views";
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 { XIcon } from "lucide-react";
import { useEffect, useState } from "react";
import { useNavigate, useParams, useSearchParams } from "react-router-dom";
import {
  useCancelClientInvite,
  useCreateClientInvite,
  usePendingClientInvites,
} from "../hooks/client_invites";
import { useEventsByTablo } from "../hooks/events";
import { useInviteUser } from "../hooks/invite";
import {
  useDeleteTabloFile,
  useDownloadTabloFile,
  useTabloFileNames,
  useUploadTabloFile,
} from "../hooks/tablo_data";
import {
  useCreateTabloFolder,
  useDeleteTabloFolder,
  useTabloFolders,
  useUpdateTabloFolder,
} from "../hooks/tablo_folders";
import { useCancelTabloInvite, usePendingTabloInvitesByTablo } from "../hooks/tablo_invites";
import {
  useTabloMembers,
  useTabloOverviewLayout,
  useTablosList,
  useUpdateTablo,
} from "../hooks/tablos";
import {
  useAllTasks,
  useCreateEtape,
  useCreateTask,
  useDeleteEtape,
  useDeleteTask,
  useTabloEtapes,
  useUpdateEtape,
  useUpdateTask,
  useUpdateTaskPositions,
} from "../hooks/tasks";
import { useUser } from "../providers/UserStoreProvider";
import { getEtapeProgressStats } from "../utils/etapeProgress";

type TabSection = SingleTabloTabId;

const TAB_SECTIONS: TabSection[] = [
  "overview",
  "etapes",
  "tasks",
  "files",
  "discussion",
  "events",
  "roadmap",
];

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

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

  const [isTaskModalOpen, setIsTaskModalOpen] = useState(false);
  const [taskModalInitialDueDate, setTaskModalInitialDueDate] = useState<Date | undefined>(
    undefined
  );
  const [taskModalDefaultAssigneeId, setTaskModalDefaultAssigneeId] = useState<string | undefined>(
    undefined
  );
  const [showAllOverviewTasks, setShowAllOverviewTasks] = useState(false);
  const [isShareDialogOpen, setIsShareDialogOpen] = useState(false);
  const [clientInviteEmail, setClientInviteEmail] = 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 { data: pendingClientInvites } = usePendingClientInvites(tabloId ?? "");
  const { mutate: createClientInvite, isPending: isCreatingClientInvite } = useCreateClientInvite();
  const { mutate: cancelClientInvite, isPending: isCancellingClientInvite } =
    useCancelClientInvite();
  const { mutate: updateTask } = useUpdateTask();
  const { mutate: deleteTask } = useDeleteTask();
  const { mutate: updateTablo, mutateAsync: updateTabloAsync } = useUpdateTablo();
  const { mutate: createTask } = useCreateTask();
  const { mutateAsync: createEtape, isPending: isCreatingEtape } = useCreateEtape();
  const { mutateAsync: updateEtape, isPending: isUpdatingEtape } = useUpdateEtape();
  const { mutateAsync: deleteEtape, isPending: isDeletingEtape } = useDeleteEtape();
  const { mutate: updateTaskPositions } = useUpdateTaskPositions();

  // Files & folders hooks
  const {
    data: foldersData,
    isLoading: foldersLoading,
    error: foldersError,
  } = useTabloFolders(tabloId ?? "");
  const { mutateAsync: downloadFile } = useDownloadTabloFile();
  const { mutateAsync: uploadFile } = useUploadTabloFile();
  const { mutateAsync: deleteFile } = useDeleteTabloFile();
  const { mutateAsync: createFolder, isPending: isCreatingFolder } = useCreateTabloFolder();
  const { mutateAsync: updateFolder, isPending: isUpdatingFolder } = useUpdateTabloFolder();
  const { mutateAsync: deleteFolder } = useDeleteTabloFolder();

  // Events hooks
  const {
    data: events,
    isLoading: eventsLoading,
    error: eventsError,
  } = useEventsByTablo(tabloId ?? null);

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

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

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

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

  const sectionParam = searchParams.get("section") as TabSection | null;
  const activeSection: TabSection =
    sectionParam && TAB_SECTIONS.includes(sectionParam) ? 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 } = getSingleTabloStatusConfig(tablo.status);
  const progress = getEtapeProgressStats(etapes);
  const isAdmin = tablo.is_admin;

  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 (
    <>
      <SingleTabloView
        tablo={tablo}
        roleLabel={isAdmin ? "Admin" : "Invité"}
        statusLabel={statusLabel}
        statusBadgeClass={badgeClass}
        progress={progress}
        activeTab={activeSection}
        onTabChange={(tabId) => setSearchParams({ section: tabId })}
        hasUnreadDiscussion={hasUnreadDiscussion}
        discussionAction={{ kind: "link", to: `/chat/${tabloId}` }}
        canInviteMembers={isAdmin}
        onOpenInviteDialog={() => setIsShareDialogOpen(true)}
      >
        {activeSection === "overview" && (
          <SingleTabloOverview
            roleLabel={isAdmin ? "Admin" : "Invité"}
            statusLabel={statusLabel}
            statusBadgeClass={badgeClass}
            description="Ce projet regroupe les tâches, fichiers et événements associés. Utilisez les onglets ci-dessus pour naviguer entre les différentes sections."
            tasks={visibleOverviewTasks}
            projectTaskCount={tabloTasks.length}
            personalTaskCount={myTabloTasks.length}
            fileNames={fileNames}
            showFileMenu={true}
            onOpenTasks={() => setSearchParams({ section: "tasks" })}
            onOpenFiles={() => setSearchParams({ section: "files" })}
            onCreateTask={() => openTaskModal(undefined, currentUser.id)}
            onToggleTaskDone={(taskId) => updateTask({ id: taskId, status: "done" })}
            showAllTasks={showAllOverviewTasks}
            onToggleShowAllTasks={() => setShowAllOverviewTasks((prev) => !prev)}
            layout={overviewLayout}
            canEditLayout={isAdmin}
            isLayoutEditMode={isLayoutEditMode}
            draggedBlock={draggedOverviewBlock}
            onToggleLayoutEditMode={() => setIsLayoutEditMode((prev) => !prev)}
            onResetLayout={handleResetOverviewLayout}
            onBlockDragStart={handleOverviewBlockDragStart}
            onBlockDragOver={handleOverviewBlockDragOver}
            onBlockDrop={handleOverviewBlockDrop}
            onBlockDragEnd={() => setDraggedOverviewBlock(null)}
          />
        )}

        {activeSection === "tasks" && (
          <TabloTasksSection
            tablo={tablo}
            isAdmin={isAdmin}
            tasks={tabloTasks}
            members={members}
            etapes={etapes}
            currentUser={currentUser}
            pendingInvites={pendingInvites?.map((inv) => ({ ...inv, id: String(inv.id) }))}
            isInvitingUser={isInvitingUser}
            isCancellingInvite={isCancellingInvite}
            onCreateTask={(task) => createTask(task)}
            onUpdateTask={(task) => updateTask(task)}
            onDeleteTask={(taskId) => deleteTask(taskId)}
            onUpdateTaskPositions={(updates) => updateTaskPositions(updates)}
            onUpdateTablo={(data) =>
              updateTabloAsync({ ...data, name: data.name ?? undefined }).then(() => undefined)
            }
            onInviteUser={inviteUser}
            onCancelInvite={(params) =>
              cancelInvite({ ...params, inviteId: Number(params.inviteId) })
            }
          />
        )}
        {activeSection === "files" && (
          <TabloFilesSection
            tablo={tablo}
            isAdmin={isAdmin}
            currentUserId={currentUser.id}
            fileNames={fileNames}
            filesLoading={false}
            filesError={null}
            folders={foldersData?.folders ?? []}
            foldersLoading={foldersLoading}
            foldersError={foldersError as Error | null}
            currentUser={currentUser}
            members={members}
            pendingInvites={pendingInvites?.map((inv) => ({ ...inv, id: String(inv.id) }))}
            isInvitingUser={isInvitingUser}
            isCancellingInvite={isCancellingInvite}
            isCreatingFolder={isCreatingFolder}
            isUpdatingFolder={isUpdatingFolder}
            onCreateFile={(params) => uploadFile(params).then(() => undefined)}
            onDeleteFile={(params) => deleteFile(params).then(() => undefined)}
            onDownloadFile={(params) => downloadFile(params).then(() => undefined)}
            onCreateFolder={(params) => createFolder(params).then(() => undefined)}
            onUpdateFolder={(params) => updateFolder(params).then(() => undefined)}
            onDeleteFolder={(params) => deleteFolder(params).then(() => undefined)}
            onUpdateTablo={(data) =>
              updateTabloAsync({ ...data, name: data.name ?? undefined }).then(() => undefined)
            }
            onInviteUser={inviteUser}
            onCancelInvite={(params) =>
              cancelInvite({ ...params, inviteId: Number(params.inviteId) })
            }
          />
        )}
        {activeSection === "discussion" && (
          <div className="flex-1 min-h-0">
            <TabloDiscussionSection
              tablo={tablo}
              isAdmin={isAdmin}
              currentUserId={currentUser.id}
              members={members}
            />
          </div>
        )}
        {activeSection === "events" && (
          <TabloEventsSection
            tablo={tablo}
            isAdmin={isAdmin}
            events={events ?? []}
            isLoading={eventsLoading}
            error={eventsError as Error | null}
            currentUser={currentUser}
            members={members}
            pendingInvites={pendingInvites?.map((inv) => ({ ...inv, id: String(inv.id) }))}
            isInvitingUser={isInvitingUser}
            isCancellingInvite={isCancellingInvite}
            onCreateEvent={() => undefined}
            onUpdateTablo={(data) =>
              updateTabloAsync({ ...data, name: data.name ?? undefined }).then(() => undefined)
            }
            onInviteUser={inviteUser}
            onCancelInvite={(params) =>
              cancelInvite({ ...params, inviteId: Number(params.inviteId) })
            }
          />
        )}

        {activeSection === "etapes" && (
          <EtapesSection
            etapes={etapes}
            tabloTasks={tabloTasks}
            tabloId={tabloId ?? ""}
            isAdmin={isAdmin}
            onCreateTask={(task) =>
              createTask({
                ...task,
                status: task.status as "todo" | "in_progress" | "in_review" | "done",
              })
            }
            onCreateEtape={(params) => createEtape(params).then(() => undefined)}
            onUpdateEtape={(params) => updateEtape(params).then(() => undefined)}
            onDeleteEtape={(params) => deleteEtape(params).then(() => undefined)}
            isCreatingEtape={isCreatingEtape}
            isUpdatingEtape={isUpdatingEtape}
            isDeletingEtape={isDeletingEtape}
          />
        )}

        {activeSection === "roadmap" && (
          <RoadmapSection
            tabloTasks={tabloTasks}
            onDateClick={openTaskModal}
            onTaskStatusChange={(taskId, status) => updateTask({ id: taskId, status })}
          />
        )}
      </SingleTabloView>

      {/* Task Create Modal */}
      {tabloId && (
        <TaskModal
          tabloId={tabloId}
          isOpen={isTaskModalOpen}
          onClose={closeTaskModal}
          members={members}
          etapes={etapes}
          initialStatus="todo"
          initialDueDate={taskModalInitialDueDate}
          defaultAssigneeId={taskModalDefaultAssigneeId}
          onCreateTask={(task) => createTask(task)}
          onUpdateTask={(task) => updateTask(task)}
          onDeleteTask={(taskId) => deleteTask(taskId)}
        />
      )}

      {/* 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">
            {/* 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>
            )}

            {/* Separator */}
            <div className="border-t border-border pt-4">
              <div className="mb-3">
                <h4 className="text-sm font-semibold text-foreground">Accès client</h4>
                <p className="text-xs text-muted-foreground">
                  Le client recevra un email pour définir son mot de passe ou, s'il a déjà un
                  compte, une notification d'accès directe à ce tablo.
                </p>
              </div>

              <div className="flex flex-col sm:flex-row gap-2">
                <Input
                  type="email"
                  value={clientInviteEmail}
                  onChange={(e) => setClientInviteEmail(e.target.value)}
                  placeholder="Email du client"
                  className="flex-1 min-h-[44px]"
                />
                {isCreatingClientInvite ? (
                  <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={() => {
                      if (tabloId && clientInviteEmail) {
                        createClientInvite(
                          { tabloId, email: clientInviteEmail },
                          { onSuccess: () => setClientInviteEmail("") }
                        );
                      }
                    }}
                    disabled={!isEmailValid(clientInviteEmail)}
                  >
                    Envoyer l'invitation
                  </Button>
                )}
              </div>

              {pendingClientInvites && pendingClientInvites.length > 0 && (
                <div className="mt-3">
                  <h4 className="text-sm font-semibold text-foreground mb-2">
                    Invitations client en attente ({pendingClientInvites.length})
                  </h4>
                  <div className="space-y-2 max-h-32 overflow-y-auto">
                    {pendingClientInvites.map((invite) => {
                      const daysUntilExpiry = Math.ceil(
                        (new Date(invite.expires_at).getTime() - Date.now()) /
                          (1000 * 60 * 60 * 24)
                      );
                      const isExpiringSoon = daysUntilExpiry < 5;
                      return (
                        <div
                          key={invite.id}
                          className="flex items-center space-x-2 p-2 bg-blue-50 dark:bg-blue-950/20 rounded-lg border border-dashed border-blue-200 dark:border-blue-900/50"
                        >
                          <div className="w-8 h-8 bg-blue-100 dark:bg-blue-900/30 rounded-full flex items-center justify-center text-blue-600 dark:text-blue-400 text-xs flex-shrink-0">
                            <svg
                              className="w-4 h-4"
                              fill="none"
                              stroke="currentColor"
                              viewBox="0 0 24 24"
                            >
                              <path
                                strokeLinecap="round"
                                strokeLinejoin="round"
                                strokeWidth={2}
                                d="M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1"
                              />
                            </svg>
                          </div>
                          <div className="flex-1 min-w-0">
                            <span className="text-xs font-medium text-foreground truncate block">
                              {invite.invited_email}
                            </span>
                            <span
                              className={`text-xs ${
                                isExpiringSoon
                                  ? "text-orange-600 dark:text-orange-400 font-medium"
                                  : "text-muted-foreground"
                              }`}
                            >
                              {isExpiringSoon && "⚠ "}
                              Expire dans {daysUntilExpiry} jour
                              {daysUntilExpiry !== 1 ? "s" : ""}
                            </span>
                          </div>
                          {isExpiringSoon && (
                            <span className="text-xs px-1.5 py-0.5 bg-orange-100 dark:bg-orange-900/30 text-orange-700 dark:text-orange-300 rounded font-medium flex-shrink-0">
                              Bientôt expiré
                            </span>
                          )}
                          <Button
                            size="sm"
                            variant="ghost"
                            className="h-7 w-7 p-0 flex-shrink-0"
                            onClick={() =>
                              cancelClientInvite({
                                tabloId: tabloId ?? "",
                                inviteId: invite.id,
                              })
                            }
                            disabled={isCancellingClientInvite || !tabloId}
                            title="Annuler l'invitation"
                          >
                            <XIcon className="w-3.5 h-3.5" />
                          </Button>
                        </div>
                      );
                    })}
                  </div>
                </div>
              )}
            </div>
          </div>
        </DialogContent>
      </Dialog>
    </>
  );
};
