"use client";

import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";

import {
  proximoEstadoAoAlternar,
  type EdicaoDaTarefa,
  type NovaTarefa,
  type Tarefa,
} from "@/lib/tarefas/tipos";

/**
 * As tarefas da organização, com as três mutações que a tela dispara.
 *
 * Extraído do PR #418 (@clinicacentrodosorrisosc-code). O `refetchInterval` do
 * original saiu: recarregar a lista inteira a cada 30 s custa uma consulta por
 * aba aberta o dia inteiro para dado que só muda quando alguém desta mesma aba
 * mexe. As mutações já invalidam a chave — o que faltava era a volta ao foco,
 * que cobre o caso real de duas pessoas do time editando ao mesmo tempo.
 */
const BASE = "/api/v1/tasks";
const CHAVE = ["crm_tasks"] as const;

export interface FiltrosDeTarefa {
  status?: string;
  priority?: string;
  lead_id?: string;
  contact_id?: string;
  /** As tarefas de UMA demanda — a seção "Tarefas desta demanda" do inbox (#2818). */
  demanda_id?: string;
  /** `true` = só o que ainda pede ação (pendente ou em andamento). */
  aberto?: boolean;
  /** De quem é: `me` (a rota resolve quem é), `ninguem` (sem responsável) ou o id de um membro. Ausente = de todos. */
  assigned_to?: string;
  /** Só as tarefas de negócios deste funil. Ausente = de todos os funis (e as tarefas soltas também). */
  pipeline_id?: string;
  /**
   * Teto de linhas desta busca. Ausente = o teto da rota (500). O QUADRO pede
   * um número menor (`LIMITE_DO_QUADRO`): ele desenha todas as colunas de uma
   * vez e não pode carregar a base inteira. A rota recusa acima do máximo dela
   * — o teto não é do navegador.
   */
  limite?: number;
}

export interface OpcoesDeTarefas {
  /** `false` segura a consulta — o dossiê fechado não precisa das tarefas dele. */
  enabled?: boolean;
  /**
   * Recarga periódica, em ms. Ausente = sem intervalo (o default da tela, que
   * só muda quando alguém desta aba mexe ou a janela volta ao foco). O contador
   * do menu pede 60 s porque as tarefas nascem de automação, sem gesto nenhum
   * aqui — mesmo intervalo do contador de Casos.
   */
  refetchInterval?: number;
}

async function leJson<T>(res: Response, oQueFalhou: string): Promise<T> {
  if (!res.ok) {
    // A mensagem do servidor quando ela existe: `fail()` nomeia o campo
    // recusado, e engolir isso deixaria a tela dizendo "erro" sobre um título
    // vazio que o usuário consegue consertar sozinho.
    const corpo = (await res.json().catch(() => null)) as { error?: { message?: string } } | null;
    throw new Error(corpo?.error?.message ?? oQueFalhou);
  }
  const json = (await res.json()) as { data: T };
  return json.data;
}

export function useTasks(filtros: FiltrosDeTarefa = {}, opcoes: OpcoesDeTarefas = {}) {
  const queryClient = useQueryClient();

  const params = new URLSearchParams();
  if (filtros.status) params.set("status", filtros.status);
  if (filtros.priority) params.set("priority", filtros.priority);
  if (filtros.lead_id) params.set("lead_id", filtros.lead_id);
  if (filtros.contact_id) params.set("contact_id", filtros.contact_id);
  if (filtros.demanda_id) params.set("demanda_id", filtros.demanda_id);
  if (filtros.aberto) params.set("aberto", "true");
  if (filtros.assigned_to) params.set("assigned_to", filtros.assigned_to);
  if (filtros.pipeline_id) params.set("pipeline_id", filtros.pipeline_id);
  if (filtros.limite) params.set("limite", String(filtros.limite));
  const qs = params.toString();

  const query = useQuery({
    queryKey: [...CHAVE, qs],
    queryFn: async () => {
      const res = await fetch(qs ? `${BASE}?${qs}` : BASE);
      return leJson<{ tasks: Tarefa[] }>(res, "Não foi possível carregar as tarefas.");
    },
    staleTime: 10_000,
    refetchOnWindowFocus: true,
    refetchInterval: opcoes.refetchInterval,
    enabled: opcoes.enabled ?? true,
  });

  // O QUADRO também: o card mostra o selo das tarefas do negócio, e quem cria
  // ou conclui uma tarefa pelo dossiê precisa ver o selo mudar ao fechar o
  // painel — senão o card segue dizendo "1 atrasada" sobre o que já foi feito.
  // O prefixo `["board"]` alcança todo quadro em cache: a tarefa não sabe em
  // qual funil o negócio está agora.
  const invalidar = () =>
    Promise.all([
      queryClient.invalidateQueries({ queryKey: CHAVE }),
      queryClient.invalidateQueries({ queryKey: ["board"] }),
    ]);

  const criar = useMutation({
    mutationFn: async (entrada: NovaTarefa) => {
      const res = await fetch(BASE, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(entrada),
      });
      return leJson<{ task: Tarefa }>(res, "Não foi possível criar a tarefa.");
    },
    onSuccess: invalidar,
  });

  const editar = useMutation({
    mutationFn: async ({ id, entrada }: { id: string; entrada: EdicaoDaTarefa }) => {
      const res = await fetch(`${BASE}/${id}`, {
        method: "PATCH",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(entrada),
      });
      return leJson<{ task: Tarefa }>(res, "Não foi possível salvar a tarefa.");
    },
    onSuccess: invalidar,
  });

  const apagar = useMutation({
    mutationFn: async (id: string) => {
      const res = await fetch(`${BASE}/${id}`, { method: "DELETE" });
      return leJson<{ deleted: boolean }>(res, "Não foi possível apagar a tarefa.");
    },
    onSuccess: invalidar,
  });

  return {
    tarefas: query.data?.tasks ?? [],
    carregando: query.isLoading,
    falhou: query.isError,
    recarregar: invalidar,
    criarTarefa: (entrada: NovaTarefa) => criar.mutateAsync(entrada),
    editarTarefa: (id: string, entrada: EdicaoDaTarefa) => editar.mutateAsync({ id, entrada }),
    apagarTarefa: (id: string) => apagar.mutateAsync(id),
    alternarConcluida: (tarefa: Tarefa) =>
      editar.mutateAsync({
        id: tarefa.id,
        // A MESMA regra da caixa da lista: `cancelled` reabre para `pending`
        // (#2549), nunca para `done`.
        entrada: { status: proximoEstadoAoAlternar(tarefa.status) },
      }),
  };
}
