"use client";

import { useCallback, useEffect, useState } from "react";
import { createClient, getBrowserUserId } from "@/lib/supabase/client";
import type { Profile, Task, Tag } from "@/types";
import { logProjectActivity } from "@/lib/project-activity";
import { logTeamAudit } from "@/lib/team-audit";
import { triggerTaskCleanup } from "@/lib/tasks/cleanup";
import { useWorkspaceStore } from "@/stores/workspace-store";
import { getNextRecurringDeadline } from "@/lib/task-recurrence";
import { playTaskDone } from "@/lib/sounds";
import { emitWebhookEvent } from "@/lib/developers/client";
import { useFocusStore } from "@/stores/focus-store";

export interface TaskWithRelations extends Task {
  tags: Tag[];
  subtasks: Task[];
}

type RestorableTaskSnapshot = TaskWithRelations;
type UpdateTaskOptions = {
  playCompletionEffects?: boolean;
};

export function useTasks(projectId?: string) {
  const [tasks, setTasks] = useState<TaskWithRelations[]>([]);
  const [loading, setLoading] = useState(true);
  const [userId, setUserId] = useState<string | null>(null);
  const supabase = createClient();
  const activeTeamId = useWorkspaceStore((state) => state.activeTeamId);
  const initialized = useWorkspaceStore((state) => state.initialized);

  useEffect(() => {
    void getBrowserUserId().then(setUserId).catch(() => setUserId(null));
  }, []);

  const fetchTasks = useCallback(async () => {
    if (!initialized) return;

    setLoading(true);
    await triggerTaskCleanup(activeTeamId);

    let query = supabase
      .from("tasks")
      .select("*, task_tags(tag_id, tags:tags(*))")
      .is("parent_task_id", null)
      .order("sort_order")
      .order("created_at", { ascending: false });

    query = activeTeamId
      ? query.eq("team_id", activeTeamId)
      : query.is("team_id", null);

    if (projectId) {
      query = query.eq("project_id", projectId);
    }

    const { data: taskData } = await query;

    if (!taskData || taskData.length === 0) {
      setTasks([]);
      setLoading(false);
      return;
    }

    const taskIds = taskData.map((t) => t.id);
    let subtaskQuery = supabase
      .from("tasks")
      .select("*")
      .in("parent_task_id", taskIds)
      .order("sort_order")
      .order("created_at", { ascending: false });

    subtaskQuery = activeTeamId
      ? subtaskQuery.eq("team_id", activeTeamId)
      : subtaskQuery.is("team_id", null);

    const { data: subtaskData } = await subtaskQuery;

    const profileIds = Array.from(
      new Set(
        [...taskData, ...(subtaskData || [])]
          .flatMap((task) => [task.assignee_id, task.reviewer_id])
          .filter(Boolean)
      )
    ) as string[];

    const profilesById = new Map<string, Profile>();
    if (profileIds.length > 0) {
      const { data: profileData } = await supabase
        .from("profiles")
        .select("id, email, full_name, avatar_url, created_at, updated_at")
        .in("id", profileIds);

      ((profileData || []) as Profile[]).forEach((profile) => {
        profilesById.set(profile.id, profile);
      });
    }

    const subtasksByParent = new Map<string, Task[]>();
    (subtaskData || []).forEach((st) => {
      const list = subtasksByParent.get(st.parent_task_id!) || [];
      list.push({
        ...st,
        assignee: st.assignee_id ? profilesById.get(st.assignee_id) : undefined,
        reviewer: st.reviewer_id ? profilesById.get(st.reviewer_id) : undefined,
      });
      subtasksByParent.set(st.parent_task_id!, list);
    });

    const result: TaskWithRelations[] = taskData.map((t) => ({
      ...t,
      assignee: t.assignee_id ? profilesById.get(t.assignee_id) : undefined,
      reviewer: t.reviewer_id ? profilesById.get(t.reviewer_id) : undefined,
      tags: (t.task_tags as Array<{ tags: Tag }>)?.map((tt) => tt.tags).filter(Boolean) || [],
      subtasks: subtasksByParent.get(t.id) || [],
    }));

    setTasks(result);
    setLoading(false);
  }, [activeTeamId, initialized, projectId, supabase]);

  useEffect(() => {
    if (!initialized) return;

    async function loadTasks() {
      await fetchTasks();
    }
    void loadTasks();
  }, [fetchTasks, initialized]);

  async function requireCurrentUserId() {
    const currentUserId = userId || (await getBrowserUserId());
    if (currentUserId && currentUserId !== userId) {
      setUserId(currentUserId);
    }
    return currentUserId;
  }

  async function fetchTaskForAutomation(taskId: string) {
    const { data } = await supabase
      .from("tasks")
      .select("*, task_tags(tag_id, tags:tags(*))")
      .eq("id", taskId)
      .single();

    if (!data) return null;

    return {
      ...data,
      tags:
        (data.task_tags as Array<{ tags: Tag }>)
          ?.map((taskTag) => taskTag.tags)
          .filter(Boolean) || [],
    };
  }

  function runTaskCompletionEffects(task: Pick<Task, "id" | "title">) {
    playTaskDone();
    const focusState = useFocusStore.getState();
    if (focusState.focusActive) {
      focusState.recordTaskCompletion(task.id, task.title);
    }
  }

  async function createTaskReviewNotification(input: {
    recipientId: string | null | undefined;
    actorId: string;
    teamId: string | null;
    taskId: string;
    title: string;
    body: string;
    details: Record<string, unknown>;
  }) {
    if (!input.recipientId || input.recipientId === input.actorId) return;

    const { error } = await supabase.from("notifications").insert({
      user_id: input.recipientId,
      actor_id: input.actorId,
      team_id: input.teamId,
      kind: "task_review",
      title: input.title,
      body: input.body,
      link: "/tasks",
      details: {
        task_id: input.taskId,
        ...input.details,
      },
    });

    if (error) {
      console.error("Failed to create task review notification", error);
    }
  }

  async function createTask(input: {
    title: string;
    description?: string;
    priority?: string;
    status?: string;
    deadline?: string | null;
    project_id?: string | null;
    goal_id?: string | null;
    assignee_id?: string | null;
    reviewer_id?: string | null;
    review_status?: Task["review_status"];
    review_notes?: string;
    parent_task_id?: string | null;
    bucket_id?: string | null;
    tag_ids?: string[];
    recurrence_pattern?: Task["recurrence_pattern"];
    recurrence_interval?: number;
  }) {
    const { tag_ids, ...taskInput } = input;
    const currentUserId = await requireCurrentUserId();
    if (!currentUserId) throw new Error("Not authenticated");

    const { data, error } = await supabase
      .from("tasks")
      .insert({
        recurrence_pattern: "none",
        recurrence_interval: 1,
        ...taskInput,
        user_id: currentUserId,
        team_id: activeTeamId,
      })
      .select()
      .single();

    if (error) throw error;

    if (tag_ids && tag_ids.length > 0) {
      await supabase.from("task_tags").insert(
        tag_ids.map((tag_id) => ({ task_id: data.id, tag_id }))
      );
    }

    if (data.reviewer_id && data.review_status === "pending_review") {
      await createTaskReviewNotification({
        recipientId: data.reviewer_id,
        actorId: currentUserId,
        teamId: activeTeamId,
        taskId: data.id,
        title: `Review requested for ${data.title}`,
        body: "A task was assigned to you for review.",
        details: {
          review_status: data.review_status,
        },
      });
    }

    await logProjectActivity(supabase, {
      userId: currentUserId,
      projectId: data.project_id,
      entityType: "task",
      entityId: data.id,
      action: "task_created",
      title: data.title,
      details: { status: data.status, priority: data.priority },
    });
    await logTeamAudit(supabase, {
      teamId: activeTeamId,
      actorId: currentUserId,
      action: "task_created",
      entityType: "task",
      entityId: data.id,
      title: data.title,
      details: {
        status: data.status,
        priority: data.priority,
        assignee_id: data.assignee_id,
        reviewer_id: data.reviewer_id,
        review_status: data.review_status,
      },
    });
    const automationTask = await fetchTaskForAutomation(data.id);

    void emitWebhookEvent({
      teamId: activeTeamId,
      eventType: "task.created",
      data: {
        task: automationTask || data,
      },
    });

    await fetchTasks();
    return data as Task;
  }

  async function updateTask(
    id: string,
    input: Partial<{
      title: string;
      description: string | null;
      priority: string;
      status: string;
      deadline: string | null;
      project_id: string | null;
      goal_id: string | null;
      assignee_id: string | null;
      reviewer_id: string | null;
      review_status: Task["review_status"];
      review_requested_at: string | null;
      reviewed_at: string | null;
      review_notes: string;
      completed_at: string | null;
      bucket_id: string | null;
      tag_ids: string[];
      recurrence_pattern: Task["recurrence_pattern"];
      recurrence_interval: number;
    }>,
    options: UpdateTaskOptions = {},
  ) {
    const { tag_ids, ...taskInput } = input;

    // Auto-set completed_at
    if (taskInput.status === "done" && !taskInput.completed_at) {
      taskInput.completed_at = new Date().toISOString();
    } else if (taskInput.status && taskInput.status !== "done") {
      taskInput.completed_at = null;
    }

    const existing = tasks.find((task) => task.id === id);
    const nextReviewStatus =
      typeof taskInput.review_status === "string"
        ? taskInput.review_status
        : existing?.review_status;
    const nextStatus =
      typeof taskInput.status === "string" ? taskInput.status : existing?.status;

    if (nextReviewStatus === "pending_review") {
      taskInput.review_requested_at =
        existing?.review_status !== "pending_review"
          ? new Date().toISOString()
          : existing.review_requested_at;
      taskInput.reviewed_at = null;
    } else if (
      nextReviewStatus === "approved" ||
      nextReviewStatus === "changes_requested"
    ) {
      taskInput.reviewed_at = new Date().toISOString();
    }

    if (
      options.playCompletionEffects !== false &&
      existing &&
      existing.status !== "done" &&
      nextStatus === "done"
    ) {
      runTaskCompletionEffects(existing);
    }

    const currentUserId = await requireCurrentUserId();

    const { error } = await supabase
      .from("tasks")
      .update(taskInput)
      .eq("id", id);

    if (error) throw error;

    if (tag_ids !== undefined) {
      await supabase.from("task_tags").delete().eq("task_id", id);
      if (tag_ids.length > 0) {
        await supabase.from("task_tags").insert(
          tag_ids.map((tag_id) => ({ task_id: id, tag_id }))
        );
      }
    }

    const taskLifecycleAction =
      existing?.status !== nextStatus && nextStatus
        ? "task_status_changed"
        : "task_updated";
    const reviewAction =
      existing?.review_status !== nextReviewStatus && nextReviewStatus
        ? nextReviewStatus === "pending_review"
          ? "task_review_requested"
          : nextReviewStatus === "approved"
          ? "task_review_approved"
          : nextReviewStatus === "changes_requested"
          ? "task_review_changes_requested"
          : "task_updated"
        : null;
    const action = reviewAction || taskLifecycleAction;

    const nextRecurrencePattern =
      typeof taskInput.recurrence_pattern === "string"
        ? taskInput.recurrence_pattern
        : existing?.recurrence_pattern || "none";
    const nextRecurrenceInterval =
      typeof taskInput.recurrence_interval === "number"
        ? taskInput.recurrence_interval
        : existing?.recurrence_interval || 1;

    if (
      existing &&
      existing.parent_task_id === null &&
      existing.status !== "done" &&
      nextStatus === "done" &&
      nextRecurrencePattern !== "none"
    ) {
      const recurringBase = {
        deadline:
          ("deadline" in taskInput
            ? (taskInput.deadline as string | null | undefined)
            : existing.deadline) || null,
        created_at: existing.created_at,
        recurrence_pattern: nextRecurrencePattern,
        recurrence_interval: nextRecurrenceInterval,
      };

      const nextDeadline = getNextRecurringDeadline(recurringBase);
      const rootSourceId = existing.source_task_id || existing.id;

      if (nextDeadline) {
        let existingNextQuery = supabase
          .from("tasks")
          .select("id")
          .eq("deadline", nextDeadline)
          .or(`id.eq.${rootSourceId},source_task_id.eq.${rootSourceId}`)
          .limit(1);

        existingNextQuery = activeTeamId
          ? existingNextQuery.eq("team_id", activeTeamId)
          : existingNextQuery.is("team_id", null);

        const { data: existingNext } = await existingNextQuery;

        if (!existingNext || existingNext.length === 0) {
          await supabase.from("tasks").insert({
            user_id: existing.user_id,
            team_id: existing.team_id,
            project_id:
              "project_id" in taskInput
                ? (taskInput.project_id as string | null | undefined)
                : existing.project_id,
            goal_id:
              "goal_id" in taskInput
                ? (taskInput.goal_id as string | null | undefined)
                : existing.goal_id,
            assignee_id:
              "assignee_id" in taskInput
                ? (taskInput.assignee_id as string | null | undefined)
                : existing.assignee_id,
            reviewer_id:
              "reviewer_id" in taskInput
                ? (taskInput.reviewer_id as string | null | undefined)
                : existing.reviewer_id,
            source_task_id: rootSourceId,
            parent_task_id: null,
            title:
              (taskInput.title as string | undefined) ||
              existing.title,
            description:
              (taskInput.description as string | null | undefined) ??
              existing.description,
            priority:
              (taskInput.priority as Task["priority"] | undefined) ||
              existing.priority,
            status: "todo",
            review_status:
              existing.review_status === "approved"
                ? "not_required"
                : existing.review_status,
            review_requested_at: null,
            reviewed_at: null,
            review_notes: "",
            deadline: nextDeadline,
            recurrence_pattern: nextRecurrencePattern,
            recurrence_interval: nextRecurrenceInterval,
          });
        }
      }
    }

    await logProjectActivity(supabase, {
      userId: currentUserId,
      projectId:
        "project_id" in taskInput
          ? (taskInput.project_id as string | null | undefined)
          : existing?.project_id,
      entityType: "task",
      entityId: id,
      action,
      title: (taskInput.title as string | undefined) || existing?.title || "Task updated",
      details:
        action === "task_status_changed"
          ? { from_status: existing?.status, to_status: nextStatus }
          : reviewAction
          ? {
              from_review_status: existing?.review_status,
              to_review_status: nextReviewStatus,
              reviewer_id:
                "reviewer_id" in taskInput
                  ? (taskInput.reviewer_id as string | null | undefined)
                  : existing?.reviewer_id,
            }
          : {},
    });
    await logTeamAudit(supabase, {
      teamId: activeTeamId,
      actorId: currentUserId,
      action,
      entityType: "task",
      entityId: id,
      title: (taskInput.title as string | undefined) || existing?.title || "Task updated",
      details:
        action === "task_status_changed"
          ? { from_status: existing?.status, to_status: nextStatus }
          : reviewAction
          ? {
              from_review_status: existing?.review_status,
              to_review_status: nextReviewStatus,
              reviewer_id:
                "reviewer_id" in taskInput
                  ? (taskInput.reviewer_id as string | null | undefined)
                  : existing?.reviewer_id,
            }
          : {
              assignee_id:
                "assignee_id" in taskInput
                  ? (taskInput.assignee_id as string | null | undefined)
                  : existing?.assignee_id,
              reviewer_id:
                "reviewer_id" in taskInput
                  ? (taskInput.reviewer_id as string | null | undefined)
                  : existing?.reviewer_id,
            },
    });

    if (
      reviewAction === "task_review_requested" &&
      (taskInput.reviewer_id || existing?.reviewer_id)
    ) {
      await createTaskReviewNotification({
        recipientId:
          (taskInput.reviewer_id as string | null | undefined) ||
          existing?.reviewer_id,
        actorId: currentUserId || "",
        teamId: activeTeamId,
        taskId: id,
        title: `Review requested for ${(taskInput.title as string | undefined) || existing?.title || "task"}`,
        body:
          (taskInput.review_notes as string | undefined) ||
          "Please review this task when you have a moment.",
        details: {
          review_status: nextReviewStatus,
        },
      });
    }

    if (
      (reviewAction === "task_review_approved" ||
        reviewAction === "task_review_changes_requested") &&
      existing
    ) {
      await createTaskReviewNotification({
        recipientId: existing.assignee_id || existing.user_id,
        actorId: currentUserId || "",
        teamId: activeTeamId,
        taskId: id,
        title:
          reviewAction === "task_review_approved"
            ? `Task approved: ${existing.title}`
            : `Changes requested: ${existing.title}`,
        body:
          (taskInput.review_notes as string | undefined) ||
          (reviewAction === "task_review_approved"
            ? "Your task was approved."
            : "A reviewer asked for changes on your task."),
        details: {
          review_status: nextReviewStatus,
          reviewer_id:
            (taskInput.reviewer_id as string | null | undefined) ||
            existing.reviewer_id,
        },
      });
    }

    const nextTask = await fetchTaskForAutomation(id);
    void emitWebhookEvent({
      teamId: activeTeamId,
      eventType: "task.updated",
      data: {
        action,
        task: nextTask || null,
        previous_task: existing || null,
      },
    });

    if (typeof taskInput.status === "string") {
      void fetch(`/api/tasks/${id}/github-sync`, {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify({ direction: "push" }),
      });
    }

    // Marking a task done is exactly when a stale duplicate (an older
    // completed run of the same recurring task, or the task itself if it was
    // already overdue) should disappear — don't wait out the cleanup
    // cooldown for that.
    if (existing && existing.status !== "done" && nextStatus === "done") {
      await triggerTaskCleanup(activeTeamId, { force: true });
    }

    await fetchTasks();
  }

  async function deleteTask(id: string) {
    const existing = tasks.find((task) => task.id === id);
    const currentUserId = await requireCurrentUserId();
    const { error } = await supabase.from("tasks").delete().eq("id", id);
    if (error) throw error;
    await logProjectActivity(supabase, {
      userId: currentUserId,
      projectId: existing?.project_id,
      entityType: "task",
      entityId: id,
      action: "task_deleted",
      title: existing?.title || "Task deleted",
    });
    await logTeamAudit(supabase, {
      teamId: activeTeamId,
      actorId: currentUserId,
      action: "task_deleted",
      entityType: "task",
      entityId: id,
      title: existing?.title || "Task deleted",
    });
    void emitWebhookEvent({
      teamId: activeTeamId,
      eventType: "task.deleted",
      data: {
        task_id: id,
        task: existing || null,
      },
    });
    await fetchTasks();
  }

  async function bulkUpdateTasks(
    ids: string[],
    input: Partial<{
      status: Task["status"];
      completed_at: string | null;
      assignee_id: string | null;
      is_focus: boolean;
      focus_order: number;
    }>
  ) {
    if (ids.length === 0) return;

    const existingTasks = tasks.filter((task) => ids.includes(task.id));
    const currentUserId = await requireCurrentUserId();
    if (!currentUserId) throw new Error("Not authenticated");

    const taskInput = { ...input };

    if (taskInput.status === "done" && !taskInput.completed_at) {
      taskInput.completed_at = new Date().toISOString();
    } else if (taskInput.status && taskInput.status !== "done") {
      taskInput.completed_at = null;
    }

    const newlyCompletedTasks =
      taskInput.status === "done"
        ? existingTasks.filter((task) => task.status !== "done")
        : [];
    if (newlyCompletedTasks.length > 0) {
      playTaskDone();
      const focusState = useFocusStore.getState();
      if (focusState.focusActive) {
        newlyCompletedTasks.forEach((task) => {
          focusState.recordTaskCompletion(task.id, task.title);
        });
      }
    }

    const { error } = await supabase.from("tasks").update(taskInput).in("id", ids);
    if (error) throw error;

    await Promise.all(
      existingTasks.map(async (task) => {
        const nextStatus = taskInput.status || task.status;
        const action =
          taskInput.status && taskInput.status !== task.status
            ? "task_status_changed"
            : "task_updated";

        await logProjectActivity(supabase, {
          userId: currentUserId,
          projectId: task.project_id,
          entityType: "task",
          entityId: task.id,
          action,
          title: task.title,
          details:
            action === "task_status_changed"
              ? { from_status: task.status, to_status: nextStatus }
              : {},
        });
        await logTeamAudit(supabase, {
          teamId: activeTeamId,
          actorId: currentUserId,
          action,
          entityType: "task",
          entityId: task.id,
          title: task.title,
          details:
            action === "task_status_changed"
              ? { from_status: task.status, to_status: nextStatus }
              : {
                  assignee_id:
                    "assignee_id" in taskInput ? taskInput.assignee_id : task.assignee_id,
                },
        });
        void emitWebhookEvent({
          teamId: activeTeamId,
          eventType: "task.updated",
          data: {
            action,
            task: {
              ...task,
              ...taskInput,
              status: nextStatus,
            },
            previous_task: task,
          },
        });
      })
    );

    await fetchTasks();
  }

  async function bulkDeleteTasks(ids: string[]) {
    if (ids.length === 0) return;

    const existingTasks = tasks.filter((task) => ids.includes(task.id));
    const currentUserId = await requireCurrentUserId();
    if (!currentUserId) throw new Error("Not authenticated");

    const { error } = await supabase.from("tasks").delete().in("id", ids);
    if (error) throw error;

    await Promise.all(
      existingTasks.map(async (task) => {
        await logProjectActivity(supabase, {
          userId: currentUserId,
          projectId: task.project_id,
          entityType: "task",
          entityId: task.id,
          action: "task_deleted",
          title: task.title,
        });
        await logTeamAudit(supabase, {
          teamId: activeTeamId,
          actorId: currentUserId,
          action: "task_deleted",
          entityType: "task",
          entityId: task.id,
          title: task.title,
        });
        void emitWebhookEvent({
          teamId: activeTeamId,
          eventType: "task.deleted",
          data: {
            task_id: task.id,
            task,
          },
        });
      })
    );

    await fetchTasks();
  }

  async function restoreTasksSnapshots(taskSnapshots: RestorableTaskSnapshot[]) {
    if (taskSnapshots.length === 0) return;

    const currentUserId = await requireCurrentUserId();
    if (!currentUserId) throw new Error("Not authenticated");

    async function insertTaskRecord(task: Task, parentTaskId?: string | null) {
      const { error } = await supabase.from("tasks").insert({
        id: task.id,
        user_id: currentUserId,
        team_id: task.team_id,
        project_id: task.project_id,
        goal_id: task.goal_id,
        assignee_id: task.assignee_id,
        reviewer_id: task.reviewer_id,
        parent_task_id:
          typeof parentTaskId === "undefined" ? task.parent_task_id : parentTaskId,
        title: task.title,
        description: task.description,
        priority: task.priority,
        status: task.status,
        review_status: task.review_status,
        review_requested_at: task.review_requested_at,
        reviewed_at: task.reviewed_at,
        review_notes: task.review_notes,
        deadline: task.deadline,
        recurrence_pattern: task.recurrence_pattern,
        recurrence_interval: task.recurrence_interval,
        source_task_id: task.source_task_id,
        is_focus: task.is_focus,
        focus_order: task.focus_order,
        sort_order: task.sort_order,
        completed_at: task.completed_at,
      });

      if (error) throw error;

      await logProjectActivity(supabase, {
        userId: currentUserId,
        projectId: task.project_id,
        entityType: "task",
        entityId: task.id,
        action: "task_created",
        title: task.title,
        details: {
          restored: true,
          status: task.status,
          priority: task.priority,
        },
      });
      await logTeamAudit(supabase, {
        teamId: task.team_id,
        actorId: currentUserId,
        action: "task_created",
        entityType: "task",
        entityId: task.id,
        title: task.title,
        details: {
          restored: true,
          status: task.status,
          priority: task.priority,
          assignee_id: task.assignee_id,
          reviewer_id: task.reviewer_id,
          review_status: task.review_status,
        },
      });
      void emitWebhookEvent({
        teamId: task.team_id,
        eventType: "task.created",
        data: {
          task,
          restored: true,
        },
      });
    }

    for (const snapshot of taskSnapshots) {
      await insertTaskRecord(snapshot);

      if (snapshot.tags.length > 0) {
        const { error: tagError } = await supabase.from("task_tags").insert(
          snapshot.tags.map((tag) => ({
            task_id: snapshot.id,
            tag_id: tag.id,
          }))
        );

        if (tagError) throw tagError;
      }

      for (const subtask of snapshot.subtasks) {
        await insertTaskRecord(subtask, snapshot.id);
      }
    }

    await fetchTasks();
  }

  async function toggleTaskStatus(id: string, currentStatus: string) {
    const newStatus = currentStatus === "done" ? "todo" : "done";
    const existing = tasks.find((task) => task.id === id);
    if (newStatus === "done" && existing && existing.status !== "done") {
      runTaskCompletionEffects(existing);
    }
    await updateTask(id, { status: newStatus }, { playCompletionEffects: false });
  }

  return {
    tasks,
    loading,
    createTask,
    updateTask,
    deleteTask,
    bulkUpdateTasks,
    bulkDeleteTasks,
    restoreTasksSnapshots,
    toggleTaskStatus,
    refetch: fetchTasks,
  };
}
