import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { buildApi, cn } from "@xtablo/shared";
import { useSession } from "@xtablo/shared/contexts/SessionContext";
import type {
  Etape,
  KanbanTask,
  KanbanTaskUpdate,
  TabloFolder,
  TaskStatus,
  UserTablo,
} from "@xtablo/shared-types";
import {
  EtapesSection,
  RoadmapSection,
  type SingleTabloTabId,
  SingleTabloView,
  TabloDiscussionSection,
  TabloEventsSection,
  TabloFilesSection,
  TabloTasksSection,
} from "@xtablo/tablo-views";
import { FolderIcon } from "lucide-react";
import { useState } from "react";
import { useParams } from "react-router-dom";
import { supabase } from "../lib/supabase";

const API_URL = import.meta.env.VITE_API_URL as string;

// ─── Local hooks ──────────────────────────────────────────────────────────────

function useAuthedApi(accessToken: string | undefined) {
  return buildApi(API_URL).create({
    headers: {
      Authorization: `Bearer ${accessToken ?? ""}`,
    },
  });
}

function useClientTablo(tabloId: string) {
  return useQuery<UserTablo>({
    queryKey: ["client-tablo", tabloId],
    queryFn: async () => {
      const { data, error } = await supabase
        .from("user_tablos")
        .select("*")
        .eq("id", tabloId)
        .single();
      if (error) throw error;
      return data as UserTablo;
    },
    enabled: !!tabloId,
  });
}

function useClientTabloTasks(tabloId: string) {
  return useQuery<KanbanTask[]>({
    queryKey: ["client-tasks", tabloId],
    queryFn: async () => {
      const { data, error } = await supabase
        .from("tasks_with_assignee")
        .select("*")
        .eq("tablo_id", tabloId)
        .eq("is_parent", false)
        .order("updated_at", { ascending: false });
      if (error) throw error;
      return (data ?? []) as KanbanTask[];
    },
    enabled: !!tabloId,
  });
}

function useClientTabloEtapes(tabloId: string) {
  return useQuery<Etape[]>({
    queryKey: ["client-etapes", tabloId],
    queryFn: async () => {
      const { data, error } = await supabase
        .from("tasks")
        .select("*")
        .eq("tablo_id", tabloId)
        .eq("is_parent", true)
        .order("position", { ascending: true });
      if (error) throw error;
      return (data ?? []) as Etape[];
    },
    enabled: !!tabloId,
  });
}

function useClientTabloEvents(tabloId: string) {
  return useQuery({
    queryKey: ["client-events", tabloId],
    queryFn: async () => {
      const { data, error } = await supabase
        .from("events_and_tablos")
        .select("*")
        .eq("tablo_id", tabloId)
        .order("start_date", { ascending: false });
      if (error) throw error;
      return data ?? [];
    },
    enabled: !!tabloId,
  });
}

function useClientTabloMembers(tabloId: string, accessToken: string | undefined) {
  const api = useAuthedApi(accessToken);
  return useQuery({
    queryKey: ["client-members", tabloId],
    queryFn: async () => {
      const { data } = await api.get<{
        members: {
          id: string;
          name: string;
          is_admin: boolean;
          email: string;
          avatar_url: string | null;
        }[];
      }>(`/api/v1/tablos/members/${tabloId}`);
      return data.members;
    },
    enabled: !!tabloId && !!accessToken,
  });
}

function useClientTabloFiles(tabloId: string, accessToken: string | undefined) {
  const api = useAuthedApi(accessToken);
  return useQuery<{ fileNames: string[] }>({
    queryKey: ["client-tablo-files", tabloId],
    queryFn: async () => {
      const { data } = await api.get(`/api/v1/tablo-data/${tabloId}/filenames`);
      return data as { fileNames: string[] };
    },
    enabled: !!tabloId && !!accessToken,
  });
}

function useClientTabloFolders(tabloId: string, accessToken: string | undefined) {
  const api = useAuthedApi(accessToken);
  return useQuery<TabloFolder[]>({
    queryKey: ["client-tablo-folders", tabloId],
    queryFn: async () => {
      const { data } = await api.get<{ folders: TabloFolder[] }>(
        `/api/v1/tablo-data/${tabloId}/folders`
      );
      return data.folders ?? [];
    },
    enabled: !!tabloId && !!accessToken,
  });
}

const invalidateClientFileQueries = (
  queryClient: ReturnType<typeof useQueryClient>,
  tabloId: string
) => {
  queryClient.invalidateQueries({ queryKey: ["client-tablo-files", tabloId] });
  queryClient.invalidateQueries({ queryKey: ["client-tablo-folders", tabloId] });
};

function useClientCreateFile(tabloId: string, accessToken: string | undefined) {
  const api = useAuthedApi(accessToken);
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: async (params: {
      tabloId: string;
      fileName: string;
      data: { content: string; contentType: string };
    }) => {
      const response = await api.post(
        `/api/v1/tablo-data/${params.tabloId}/file/${params.fileName}`,
        params.data
      );
      if (response.status !== 200) {
        throw new Error("Failed to create file");
      }
      return response.data;
    },
    onSuccess: () => invalidateClientFileQueries(queryClient, tabloId),
  });
}

function useClientDownloadFile(accessToken: string | undefined) {
  const api = useAuthedApi(accessToken);

  return useMutation({
    mutationFn: async ({ tabloId, fileName }: { tabloId: string; fileName: string }) => {
      const response = await api.get(`/api/v1/tablo-data/${tabloId}/${fileName}`);
      if (response.status !== 200) {
        throw new Error("Failed to download file");
      }

      const fileData = response.data as { content: string; contentType?: string };
      let blob: Blob;

      if (fileData.content.startsWith("data:")) {
        const fileResponse = await fetch(fileData.content);
        blob = await fileResponse.blob();
      } else {
        blob = new Blob([fileData.content], {
          type: fileData.contentType || "application/octet-stream",
        });
      }

      const url = window.URL.createObjectURL(blob);
      const link = document.createElement("a");
      link.href = url;
      link.download = fileName;
      document.body.appendChild(link);
      link.click();
      document.body.removeChild(link);
      window.URL.revokeObjectURL(url);
    },
  });
}

function useClientCreateFolder(tabloId: string, accessToken: string | undefined) {
  const api = useAuthedApi(accessToken);
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: async (params: {
      tabloId: string;
      name: string;
      description: string;
      createdBy: string;
    }) => {
      const response = await api.post(`/api/v1/tablo-data/${params.tabloId}/folders`, {
        name: params.name,
        description: params.description,
      });
      if (response.status !== 200) {
        throw new Error("Failed to create folder");
      }
      return response.data;
    },
    onSuccess: () => invalidateClientFileQueries(queryClient, tabloId),
  });
}

function useClientUpdateFolder(tabloId: string, accessToken: string | undefined) {
  const api = useAuthedApi(accessToken);
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: async (params: {
      tabloId: string;
      folderId: string;
      name: string;
      description: string;
    }) => {
      const response = await api.put(
        `/api/v1/tablo-data/${params.tabloId}/folders/${params.folderId}`,
        {
          name: params.name,
          description: params.description,
        }
      );
      if (response.status !== 200) {
        throw new Error("Failed to update folder");
      }
      return response.data;
    },
    onSuccess: () => invalidateClientFileQueries(queryClient, tabloId),
  });
}

function useClientDeleteFolder(tabloId: string, accessToken: string | undefined) {
  const api = useAuthedApi(accessToken);
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: async (params: { tabloId: string; folderId: string; folderName: string }) => {
      const response = await api.delete(
        `/api/v1/tablo-data/${params.tabloId}/folders/${params.folderId}`
      );
      if (response.status !== 200) {
        throw new Error("Failed to delete folder");
      }
      return response.data;
    },
    onSuccess: () => invalidateClientFileQueries(queryClient, tabloId),
  });
}

type ClientTaskCreateInput = {
  tablo_id: string;
  title: string;
  status?: TaskStatus | string;
  parent_task_id?: string | null;
  is_parent?: boolean;
  position?: number;
  description?: string | null;
  assignee_id?: string | null;
  due_date?: string | null;
};

const invalidateClientTaskQueries = (
  queryClient: ReturnType<typeof useQueryClient>,
  tabloId: string
) => {
  queryClient.invalidateQueries({ queryKey: ["client-tasks", tabloId] });
};

function useClientCreateTask(tabloId: string) {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: async (task: ClientTaskCreateInput) => {
      const { data, error } = await supabase
        .from("tasks")
        .insert({
          tablo_id: task.tablo_id,
          title: task.title,
          status: (task.status as TaskStatus | undefined) ?? "todo",
          assignee_id: task.assignee_id ?? null,
          position: task.position ?? 0,
          parent_task_id: task.parent_task_id ?? null,
          is_parent: task.is_parent ?? false,
          description: task.description ?? null,
          due_date: task.due_date ?? null,
        })
        .select()
        .single();

      if (error) throw error;
      return data;
    },
    onSuccess: () => invalidateClientTaskQueries(queryClient, tabloId),
  });
}

function useClientUpdateTask(tabloId: string) {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: async ({
      id,
      tablo_id: _tabloId,
      ...updates
    }: KanbanTaskUpdate & { id: string; tablo_id?: string }) => {
      const { data, error } = await supabase
        .from("tasks")
        .update(updates)
        .eq("id", id)
        .select()
        .single();

      if (error) throw error;
      return data;
    },
    onSuccess: () => invalidateClientTaskQueries(queryClient, tabloId),
  });
}

function useClientDeleteTask(tabloId: string) {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: async (taskId: string) => {
      const { error } = await supabase.from("tasks").delete().eq("id", taskId);
      if (error) throw error;
      return taskId;
    },
    onSuccess: () => invalidateClientTaskQueries(queryClient, tabloId),
  });
}

function useClientUpdateTaskPositions(tabloId: string) {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: async (
      updates: Array<{
        id: string;
        position: number;
        status?: TaskStatus;
        parent_task_id?: string | null;
      }>
    ) => {
      const results = await Promise.all(
        updates.map(({ id, position, status, parent_task_id }) =>
          supabase
            .from("tasks")
            .update({
              position,
              ...(status && { status }),
              ...(parent_task_id !== undefined ? { parent_task_id } : {}),
            })
            .eq("id", id)
        )
      );

      const errors = results.filter((result) => result.error);
      if (errors.length > 0) {
        throw new Error("Failed to update some task positions");
      }

      return updates;
    },
    onSuccess: () => invalidateClientTaskQueries(queryClient, tabloId),
  });
}

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

function getEtapeProgressStats(etapes: Etape[]) {
  const total = etapes.length;
  const done = etapes.filter((etape) => etape.status === "done").length;
  const started = etapes.filter((etape) =>
    new Set(["in_progress", "in_review", "done"]).has(etape.status ?? "todo")
  ).length;

  if (total === 0) {
    return {
      startedPercentage: 0,
      donePercentage: 0,
    };
  }

  return {
    startedPercentage: Math.round((started / total) * 100),
    donePercentage: Math.round((done / total) * 100),
  };
}

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

export function ClientTabloPage() {
  const { tabloId } = useParams<{ tabloId: string }>();
  const { session } = useSession();
  const [activeTab, setActiveTab] = useState<SingleTabloTabId>("overview");

  const accessToken = session?.access_token;
  const currentUserId = session?.user.id ?? "";

  const { data: tablo, isLoading: tabloLoading } = useClientTablo(tabloId ?? "");
  const { data: tasks = [] } = useClientTabloTasks(tabloId ?? "");
  const { data: etapes = [] } = useClientTabloEtapes(tabloId ?? "");
  const {
    data: events,
    isLoading: eventsLoading,
    error: eventsError,
  } = useClientTabloEvents(tabloId ?? "");
  const { data: members = [] } = useClientTabloMembers(tabloId ?? "", accessToken);
  const {
    data: filesData,
    isLoading: filesLoading,
    error: filesError,
  } = useClientTabloFiles(tabloId ?? "", accessToken);
  const {
    data: folders = [],
    isLoading: foldersLoading,
    error: foldersError,
  } = useClientTabloFolders(tabloId ?? "", accessToken);
  const { mutate: createTask } = useClientCreateTask(tabloId ?? "");
  const { mutate: updateTask } = useClientUpdateTask(tabloId ?? "");
  const { mutate: deleteTask } = useClientDeleteTask(tabloId ?? "");
  const { mutate: updateTaskPositions } = useClientUpdateTaskPositions(tabloId ?? "");
  const { mutateAsync: createFile } = useClientCreateFile(tabloId ?? "", accessToken);
  const { mutateAsync: downloadFile } = useClientDownloadFile(accessToken);
  const { mutateAsync: createFolder } = useClientCreateFolder(tabloId ?? "", accessToken);
  const { mutateAsync: updateFolder } = useClientUpdateFolder(tabloId ?? "", accessToken);
  const { mutateAsync: deleteFolder } = useClientDeleteFolder(tabloId ?? "", accessToken);

  const fileNames = (filesData?.fileNames ?? []).filter((f) => !f.startsWith("."));

  const currentUser = { id: currentUserId, avatar_url: null };

  if (tabloLoading) {
    return (
      <div className="flex items-center justify-center h-64">
        <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-primary" />
      </div>
    );
  }

  if (!tablo) {
    return (
      <div className="text-center py-16">
        <p className="text-muted-foreground">Projet introuvable.</p>
      </div>
    );
  }

  const { label: statusLabel, badgeClass } = getStatusConfig(tablo.status);
  const progress = getEtapeProgressStats(etapes);

  return (
    <SingleTabloView
      tablo={tablo}
      roleLabel="Invité"
      statusLabel={statusLabel}
      statusBadgeClass={badgeClass}
      progress={progress}
      activeTab={activeTab}
      onTabChange={setActiveTab}
      discussionAction={{ kind: "button", onClick: () => setActiveTab("discussion") }}
    >
      {activeTab === "overview" && (
        <div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
          <div className="lg:col-span-2 space-y-6">
            <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>

            <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>
              </div>
              <div className="divide-y divide-gray-200 dark:divide-gray-700">
                {tasks.length === 0 ? (
                  <div className="p-6 text-center text-muted-foreground text-sm">Aucune tâche</div>
                ) : (
                  tasks.slice(0, 5).map((task) => (
                    <button
                      key={task.id}
                      type="button"
                      onClick={() =>
                        updateTask({
                          id: task.id,
                          status: task.status === "done" ? "todo" : "done",
                        })
                      }
                      className="flex w-full items-center gap-3 p-4 text-left transition-colors hover:bg-gray-50 dark:hover:bg-gray-800"
                    >
                      <div
                        className={cn(
                          "w-5 h-5 rounded-full border-2 shrink-0",
                          task.status === "done"
                            ? "bg-green-500 border-green-500"
                            : "border-gray-300 dark:border-gray-600"
                        )}
                      />
                      <p
                        className={cn(
                          "text-sm font-medium truncate",
                          task.status === "done"
                            ? "text-gray-400 line-through"
                            : "text-gray-900 dark:text-gray-100"
                        )}
                      >
                        {task.title}
                      </p>
                    </button>
                  ))
                )}
              </div>
            </div>
          </div>

          <div className="space-y-6">
            <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>
              </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 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">
                        <FolderIcon 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>
                    </div>
                  ))
                )}
              </div>
            </div>

            <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">{tasks.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">Invité</dd>
                </div>
              </dl>
            </div>
          </div>
        </div>
      )}

      {activeTab === "etapes" && (
        <EtapesSection
          etapes={etapes}
          tabloTasks={tasks}
          tabloId={tablo.id}
          isAdmin={false}
          onCreateTask={(task) => createTask(task)}
          onCreateEtape={async () => undefined}
          onTaskStatusChange={(taskId, status) => updateTask({ id: taskId, status })}
        />
      )}

      {activeTab === "tasks" && (
        <TabloTasksSection
          tablo={tablo}
          isAdmin={false}
          tasks={tasks}
          members={members}
          etapes={etapes}
          currentUser={currentUser}
          onCreateTask={(task) => createTask(task)}
          onUpdateTask={(task) => updateTask(task)}
          onDeleteTask={(taskId) => deleteTask(taskId)}
          onUpdateTaskPositions={(updates) => updateTaskPositions(updates)}
        />
      )}

      {activeTab === "files" && (
        <TabloFilesSection
          tablo={tablo}
          isAdmin={false}
          isReadOnly={false}
          canUploadFiles={true}
          canManageFolders={true}
          canDeleteFiles={false}
          currentUserId={currentUserId}
          fileNames={fileNames}
          filesLoading={filesLoading}
          filesError={filesError instanceof Error ? filesError : null}
          folders={folders}
          foldersLoading={foldersLoading}
          foldersError={foldersError instanceof Error ? foldersError : null}
          currentUser={currentUser}
          members={members}
          onCreateFile={(params) => createFile(params)}
          onDownloadFile={(params) => downloadFile(params)}
          onCreateFolder={(params) => createFolder(params)}
          onUpdateFolder={(params) => updateFolder(params)}
          onDeleteFolder={(params) => deleteFolder(params)}
        />
      )}

      {activeTab === "discussion" && (
        <TabloDiscussionSection
          tablo={tablo}
          isAdmin={false}
          currentUserId={currentUserId}
          members={members}
        />
      )}

      {activeTab === "events" && (
        <TabloEventsSection
          tablo={tablo}
          isAdmin={false}
          isReadOnly={true}
          events={events as Parameters<typeof TabloEventsSection>[0]["events"]}
          isLoading={eventsLoading}
          error={eventsError instanceof Error ? eventsError : null}
          currentUser={currentUser}
          members={members}
        />
      )}

      {activeTab === "roadmap" && (
        <RoadmapSection
          tabloTasks={tasks}
          onDateClick={() => undefined}
          onTaskStatusChange={(taskId, status) => updateTask({ id: taskId, status })}
        />
      )}
    </SingleTabloView>
  );
}
