import type { QueryClient } from "@tanstack/react-query";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { toast } from "@xtablo/shared";
import type {
  Etape,
  KanbanTask,
  KanbanTaskInsert,
  KanbanTaskUpdate,
  TaskStatus,
} from "@xtablo/shared-types";
import { supabase } from "../lib/supabase";

type CreateEtapeInput = {
  tabloId: string;
  title: string;
  description?: string | null;
  position?: number;
  due_date?: string | null;
};

type UpdateEtapeInput = {
  id: string;
  tabloId: string;
  title?: string;
  description?: string | null;
  position?: number;
  due_date?: string | null;
};

type DeleteEtapeInput = {
  id: string;
  tabloId: string;
};

type ReorderEtapesInput = {
  tabloId: string;
  updates: Array<{ id: string; position: number }>;
};

const invalidateEtapeCaches = (queryClient: QueryClient, tabloId?: string) => {
  queryClient.invalidateQueries({ queryKey: ["tablo-etapes"] });
  if (tabloId) {
    queryClient.invalidateQueries({ queryKey: ["tablo-etapes", tabloId] });
    queryClient.invalidateQueries({ queryKey: ["tasks", "tablo", tabloId] });
  }
  queryClient.invalidateQueries({ queryKey: ["tasks"] });
};

// Fetch all tasks across all tablos where user is a member
export const useAllTasks = () => {
  return useQuery({
    queryKey: ["tasks", "all"],
    queryFn: async () => {
      // Fetch tasks (RLS will automatically filter to tablos user has access to)
      const { data: tasks, error: tasksError } = await supabase
        .from("tasks_with_assignee")
        .select("*")
        .eq("is_parent", false)
        .order("updated_at", { ascending: false });

      if (tasksError) throw tasksError;

      // Get unique tablo IDs
      const tabloIds = [...new Set(tasks?.map((t) => t.tablo_id).filter(Boolean) || [])];

      // Fetch tablo information (only if we have tablo IDs)
      let tablos: { id: string; name: string; color: string | null }[] = [];
      if (tabloIds.length > 0) {
        const { data, error: tablosError } = await supabase
          .from("tablos")
          .select("id, name, color")
          .in("id", tabloIds);

        if (tablosError) throw tablosError;
        tablos = data || [];
      }

      // Create a map for quick lookup
      const tabloMap = new Map(
        tablos?.map((t) => [t.id, { id: t.id, name: t.name, color: t.color }]) || []
      );

      // Merge tasks with tablo information
      return (tasks || []).map((task) => ({
        ...task,
        tablos: tabloMap.get(task.tablo_id) || null,
      })) as (KanbanTask & {
        tablos: { id: string; name: string; color: string | null } | null;
      })[];
    },
  });
};

// Fetch all tasks for a specific tablo
export const useTasksByTablo = (tabloId: string | undefined, options?: { assigneeId?: string }) => {
  const assigneeId = options?.assigneeId;

  return useQuery({
    queryKey: ["tasks", "tablo", tabloId, assigneeId ?? "all-assignees"],
    queryFn: async () => {
      let query = supabase
        .from("tasks_with_assignee")
        .select("*")
        .eq("tablo_id", tabloId)
        .eq("is_parent", false)
        .order("position", { ascending: true });

      if (assigneeId) {
        query = query.eq("assignee_id", assigneeId);
      }

      const { data, error } = await query;

      if (error) throw error;
      return data as KanbanTask[];
    },
    enabled: !!tabloId,
  });
};

// Fetch single task
export const useTask = (taskId: string | undefined) => {
  return useQuery({
    queryKey: ["tasks", "single", taskId],
    queryFn: async () => {
      const { data, error } = await supabase
        .from("tasks_with_assignee")
        .select("*")
        .eq("id", taskId)
        .single();

      if (error) throw error;
      return data as KanbanTask;
    },
    enabled: !!taskId,
  });
};

// // Fetch tasks assigned to current user
// export const useMyTasks = (tabloId?: string) => {
//   const user = useUser();

//   return useQuery({
//     queryKey: tabloId ? ["tasks", "my", tabloId] : ["tasks", "my"],
//     queryFn: async () => {
//       let query = supabase
//         .from("tasks_with_assignee")
//         .select("*")
//         .eq("assignee_id", user.id)
//         .order("position", { ascending: true });

//       if (tabloId) {
//         query = query.eq("tablo_id", tabloId);
//       }

//       const { data, error } = await query;

//       if (error) throw error;
//       return data as KanbanTask[];
//     },
//     enabled: !!user.id,
//   });
// };

// Create new task
export const useCreateTask = () => {
  const queryClient = useQueryClient();

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

      if (error) throw error;
      return data;
    },
    onSuccess: () => {
      // Invalidate tasks list to refetch
      queryClient.invalidateQueries({ queryKey: ["tasks"] });

      toast.add(
        {
          title: "Tâche créée",
          description: "La tâche a été créée avec succès",
          type: "success",
        },
        { timeout: 3000 }
      );
    },
    onError: (error) => {
      toast.add(
        {
          title: "Erreur",
          description: "Impossible de créer la tâche",
          type: "error",
        },
        { timeout: 5000 }
      );
      console.error("Error creating task:", error);
    },
  });
};

// Update task
export const useUpdateTask = () => {
  const queryClient = useQueryClient();

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

      if (error) throw error;
      return data;
    },
    onSuccess: () => {
      // Invalidate relevant queries
      queryClient.invalidateQueries({ queryKey: ["tasks"] });

      toast.add(
        {
          title: "Tâche mise à jour",
          description: "La tâche a été mise à jour avec succès",
          type: "success",
        },
        { timeout: 3000 }
      );
    },
    onError: (error) => {
      toast.add(
        {
          title: "Erreur",
          description: "Impossible de mettre à jour la tâche",
          type: "error",
        },
        { timeout: 5000 }
      );
      console.error("Error updating task:", error);
    },
  });
};

// Delete task (soft delete could be added if needed)
export const useDeleteTask = () => {
  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: () => {
      // Invalidate all task queries
      queryClient.invalidateQueries({ queryKey: ["tasks"] });

      toast.add(
        {
          title: "Tâche supprimée",
          description: "La tâche a été supprimée avec succès",
          type: "success",
        },
        { timeout: 3000 }
      );
    },
    onError: (error) => {
      toast.add(
        {
          title: "Erreur",
          description: "Impossible de supprimer la tâche",
          type: "error",
        },
        { timeout: 5000 }
      );
      console.error("Error deleting task:", error);
    },
  });
};

// Batch update task positions (useful for drag and drop)
export const useUpdateTaskPositions = () => {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: async (
      updates: Array<{
        id: string;
        position: number;
        status?: TaskStatus;
        parent_task_id?: string | null;
      }>
    ) => {
      const promises = 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 results = await Promise.all(promises);
      const errors = results.filter((r) => r.error);

      if (errors.length > 0) {
        throw new Error("Failed to update some task positions");
      }

      return updates;
    },
    onSuccess: () => {
      // Invalidate queries for affected tablos
      queryClient.invalidateQueries({ queryKey: ["tasks"] });
    },
    onError: (error) => {
      toast.add(
        {
          title: "Erreur",
          description: "Impossible de réorganiser les tâches",
          type: "error",
        },
        { timeout: 5000 }
      );
      console.error("Error updating task positions:", error);
    },
  });
};

// Fetch Etapes (parent tasks) for a tablo
export const useTabloEtapes = (tabloId: string | undefined) => {
  return useQuery({
    queryKey: ["tablo-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,
  });
};

export const useCreateEtape = () => {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: async ({ tabloId, title, description, position, due_date }: CreateEtapeInput) => {
      const { data, error } = await supabase
        .from("tasks")
        .insert({
          tablo_id: tabloId,
          title,
          description: description ?? null,
          status: "todo",
          position: position ?? 0,
          is_parent: true,
          due_date: due_date ?? null,
        })
        .select()
        .single();

      if (error) throw error;
      return data as Etape;
    },
    onSuccess: (_data, variables) => {
      invalidateEtapeCaches(queryClient, variables.tabloId);
      toast.add(
        {
          title: "Étape créée",
          description: "La nouvelle Étape a été ajoutée avec succès",
          type: "success",
        },
        { timeout: 3000 }
      );
    },
    onError: (error) => {
      toast.add(
        {
          title: "Erreur",
          description: "Impossible de créer l'Étape",
          type: "error",
        },
        { timeout: 5000 }
      );
      console.error("Error creating Etape:", error);
    },
  });
};

export const useUpdateEtape = () => {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: async ({
      id,
      tabloId,
      title,
      description,
      position,
      due_date,
    }: UpdateEtapeInput) => {
      const updates: Record<string, unknown> = {};
      if (title !== undefined) updates.title = title;
      if (description !== undefined) updates.description = description;
      if (position !== undefined) updates.position = position;
      if (due_date !== undefined) updates.due_date = due_date;

      if (Object.keys(updates).length === 0) {
        throw new Error("Aucune modification fournie pour l'Étape");
      }

      const { data, error } = await supabase
        .from("tasks")
        .update(updates)
        .eq("id", id)
        .eq("tablo_id", tabloId)
        .eq("is_parent", true)
        .select()
        .single();

      if (error) throw error;
      return data as Etape;
    },
    onSuccess: (_data, variables) => {
      invalidateEtapeCaches(queryClient, variables.tabloId);
      toast.add(
        {
          title: "Étape mise à jour",
          description: "Les modifications de l'Étape ont été enregistrées",
          type: "success",
        },
        { timeout: 3000 }
      );
    },
    onError: (error) => {
      toast.add(
        {
          title: "Erreur",
          description: "Impossible de mettre à jour l'Étape",
          type: "error",
        },
        { timeout: 5000 }
      );
      console.error("Error updating Etape:", error);
    },
  });
};

export const useDeleteEtape = () => {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: async ({ id, tabloId }: DeleteEtapeInput) => {
      const { error } = await supabase
        .from("tasks")
        .delete()
        .eq("id", id)
        .eq("tablo_id", tabloId)
        .eq("is_parent", true);

      if (error) throw error;
      return id;
    },
    onSuccess: (_data, variables) => {
      invalidateEtapeCaches(queryClient, variables.tabloId);
      toast.add(
        {
          title: "Étape supprimée",
          description: "L'Étape a été supprimée avec succès",
          type: "success",
        },
        { timeout: 3000 }
      );
    },
    onError: (error) => {
      toast.add(
        {
          title: "Erreur",
          description: "Impossible de supprimer l'Étape",
          type: "error",
        },
        { timeout: 5000 }
      );
      console.error("Error deleting Etape:", error);
    },
  });
};

export const useReorderEtapes = () => {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: async ({ tabloId, updates }: ReorderEtapesInput) => {
      const results = await Promise.all(
        updates.map(({ id, position }) =>
          supabase
            .from("tasks")
            .update({ position })
            .eq("id", id)
            .eq("tablo_id", tabloId)
            .eq("is_parent", true)
        )
      );

      const errors = results.filter((r) => r.error);
      if (errors.length > 0) {
        throw new Error("Failed to reorder Étapes");
      }

      return updates;
    },
    onSuccess: (_data, variables) => {
      invalidateEtapeCaches(queryClient, variables.tabloId);
    },
    onError: (error) => {
      toast.add(
        {
          title: "Erreur",
          description: "Impossible de réorganiser les Étapes",
          type: "error",
        },
        { timeout: 5000 }
      );
      console.error("Error reordering Etapes:", error);
    },
  });
};
