import { queryOptions, useMutation, useQueryClient } from '@tanstack/react-query'
import { toast } from 'sonner'
import { supabase } from '@/integrations/supabase/client'
import type { ChecklistItem, Task } from '@/integrations/supabase/types'

export const tasksKey = ['tasks'] as const
export const checklistKey = (taskId: string) => ['checklist', taskId] as const

async function currentUserId() {
  const { data, error } = await supabase.auth.getUser()
  if (error || !data.user) throw new Error('Sua sessão expirou. Entre novamente.')
  return data.user.id
}

export const tasksQuery = queryOptions({
  queryKey: tasksKey,
  queryFn: async (): Promise<Task[]> => {
    const { data, error } = await supabase.from('tasks').select('*').order('position').order('created_at')
    if (error) throw error
    return data as Task[]
  },
})

export function checklistQuery(taskId: string) {
  return queryOptions({
    queryKey: checklistKey(taskId),
    queryFn: async (): Promise<ChecklistItem[]> => {
      const { data, error } = await supabase.from('checklist_items').select('*').eq('task_id', taskId).order('position').order('created_at')
      if (error) throw error
      return data as ChecklistItem[]
    },
    enabled: Boolean(taskId),
  })
}

export function useCreateTask() {
  const queryClient = useQueryClient()
  return useMutation({
    mutationFn: async (input: Partial<Task> & Pick<Task, 'title'>) => {
      const user_id = await currentUserId()
      const current = queryClient.getQueryData<Task[]>(tasksKey) ?? []
      const position = input.position ?? (Math.max(0, ...current.map((t) => t.position)) + 10)
      const { data, error } = await supabase.from('tasks').insert({ ...input, title: input.title.trim(), user_id, position }).select().single()
      if (error) throw error
      return data as Task
    },
    onSuccess: (task) => {
      queryClient.setQueryData<Task[]>(tasksKey, (old = []) => [...old, task].sort((a,b) => a.position-b.position))
      toast.success('Tarefa criada')
    },
    onError: (error) => toast.error('Não foi possível criar a tarefa', { description: error.message }),
  })
}

export function useUpdateTask() {
  const queryClient = useQueryClient()
  return useMutation({
    mutationFn: async ({ id, patch }: { id: string; patch: Partial<Task> }) => {
      const { data, error } = await supabase.from('tasks').update(patch).eq('id', id).select().single()
      if (error) throw error
      return data as Task
    },
    onMutate: async ({ id, patch }) => {
      await queryClient.cancelQueries({ queryKey: tasksKey })
      const snapshot = queryClient.getQueryData<Task[]>(tasksKey)
      queryClient.setQueryData<Task[]>(tasksKey, (old = []) => old.map((task) => task.id === id ? { ...task, ...patch, updated_at: new Date().toISOString() } : task))
      return { snapshot }
    },
    onError: (error, _vars, context) => {
      if (context?.snapshot) queryClient.setQueryData(tasksKey, context.snapshot)
      toast.error('Não foi possível atualizar', { description: error.message })
    },
    onSettled: () => queryClient.invalidateQueries({ queryKey: tasksKey }),
  })
}

function descendants(tasks: Task[], id: string): Set<string> {
  const ids = new Set([id])
  let changed = true
  while (changed) {
    changed = false
    for (const task of tasks) if (task.parent_task_id && ids.has(task.parent_task_id) && !ids.has(task.id)) { ids.add(task.id); changed = true }
  }
  return ids
}

export function useDeleteTask() {
  const queryClient = useQueryClient()
  return useMutation({
    mutationFn: async (id: string) => {
      const { error } = await supabase.from('tasks').delete().eq('id', id)
      if (error) throw error
      return id
    },
    onMutate: async (id) => {
      await queryClient.cancelQueries({ queryKey: tasksKey })
      const snapshot = queryClient.getQueryData<Task[]>(tasksKey) ?? []
      const removed = descendants(snapshot, id)
      queryClient.setQueryData<Task[]>(tasksKey, snapshot.filter((task) => !removed.has(task.id)))
      return { snapshot }
    },
    onError: (error, _id, context) => {
      queryClient.setQueryData(tasksKey, context?.snapshot)
      toast.error('Não foi possível excluir', { description: error.message })
    },
    onSuccess: () => toast.success('Tarefa excluída'),
    onSettled: () => queryClient.invalidateQueries({ queryKey: tasksKey }),
  })
}

export function useToggleComplete() {
  const update = useUpdateTask()
  return { ...update, mutate: (task: Task) => update.mutate({ id: task.id, patch: task.status === 'done' ? { status: 'todo', completed_at: null } : { status: 'done', completed_at: new Date().toISOString() } }) }
}

export function useCreateChecklistItem(taskId: string) {
  const queryClient = useQueryClient()
  return useMutation({
    mutationFn: async (title: string) => {
      const user_id = await currentUserId()
      const current = queryClient.getQueryData<ChecklistItem[]>(checklistKey(taskId)) ?? []
      const position = Math.max(0, ...current.map((i) => i.position)) + 10
      const { data, error } = await supabase.from('checklist_items').insert({ task_id: taskId, user_id, title: title.trim(), position }).select().single()
      if (error) throw error
      return data as ChecklistItem
    },
    onSuccess: (item) => { queryClient.setQueryData<ChecklistItem[]>(checklistKey(taskId), (old = []) => [...old, item]); toast.success('Item adicionado') },
    onError: (error) => toast.error('Erro ao adicionar item', { description: error.message }),
  })
}

export function useUpdateChecklistItem(taskId: string) {
  const queryClient = useQueryClient()
  return useMutation({
    mutationFn: async ({ id, patch }: { id:string; patch:Partial<ChecklistItem> }) => {
      const { data, error } = await supabase.from('checklist_items').update(patch).eq('id', id).select().single()
      if (error) throw error
      return data as ChecklistItem
    },
    onMutate: async ({ id, patch }) => {
      await queryClient.cancelQueries({ queryKey: checklistKey(taskId) })
      const snapshot = queryClient.getQueryData<ChecklistItem[]>(checklistKey(taskId))
      queryClient.setQueryData<ChecklistItem[]>(checklistKey(taskId), (old = []) => old.map((item) => item.id === id ? { ...item, ...patch } : item).sort((a,b)=>a.position-b.position))
      return { snapshot }
    },
    onError: (error, _v, ctx) => { queryClient.setQueryData(checklistKey(taskId), ctx?.snapshot); toast.error('Erro ao atualizar item', { description:error.message }) },
    onSettled: () => queryClient.invalidateQueries({ queryKey: checklistKey(taskId) }),
  })
}

export function useDeleteChecklistItem(taskId: string) {
  const queryClient = useQueryClient()
  return useMutation({
    mutationFn: async (id: string) => { const { error } = await supabase.from('checklist_items').delete().eq('id', id); if (error) throw error; return id },
    onSuccess: (id) => queryClient.setQueryData<ChecklistItem[]>(checklistKey(taskId), (old = []) => old.filter((item) => item.id !== id)),
    onError: (error) => toast.error('Erro ao excluir item', { description:error.message }),
  })
}
