import { NextResponse } from "next/server";
import { acessoDoChat } from "@/lib/chats/acesso";
import { createAdminClient } from "@/lib/supabase-server";

/*
  Encerrar (e reabrir) um atendimento, e dizer em que pe ele esta.

  Sem isso a lista vira depósito: a duvida respondida ha tres semanas fica no
  meio das de hoje e ninguem sabe o que ainda esta em aberto. Encerrar nao apaga
  nada — a conversa some da lista de abertas e volta sozinha se a pessoa
  escrever de novo, contando mais uma visita.

  O estagio (novo, atendendo, negociando, fechado, perdido) mora na propria
  conversa, e nao numa tela de funil a parte: e a mesma pessoa, o mesmo fio, e
  ninguem precisa manter dois lugares atualizados.
*/

const ESTAGIOS = new Set(["novo", "atendendo", "negociando", "fechado", "perdido"]);

function texto(valor: unknown) {
  return String(valor ?? "").trim();
}

export async function PATCH(request: Request, context: { params: Promise<{ threadId: string }> }) {
  const { threadId } = await context.params;
  const acesso = await acessoDoChat();
  if ("erro" in acesso) return acesso.erro;
  if (!acesso.podeResponderLoja) return NextResponse.json({ error: "Sem permissao." }, { status: 403 });

  const corpo = (await request.json().catch(() => null)) as
    | { encerrar?: unknown; estagio?: unknown; responsavel?: unknown; etiquetas?: unknown }
    | null;
  const encerrar = corpo?.encerrar !== false;
  const estagioPedido = texto(corpo?.estagio);
  const mudandoEstagio = Object.prototype.hasOwnProperty.call(corpo || {}, "estagio");
  const mudandoResponsavel = Object.prototype.hasOwnProperty.call(corpo || {}, "responsavel");
  const mudandoEtiquetas = Object.prototype.hasOwnProperty.call(corpo || {}, "etiquetas");
  const mudandoRetomar = Object.prototype.hasOwnProperty.call(corpo || {}, "retomarEm");

  const admin = createAdminClient();
  const { data } = await admin
    .from("chat_threads")
    .select("id,user_id,kind,member_a,member_b")
    .eq("id", threadId)
    .maybeSingle();

  const conversa = data as
    | { id: string; user_id: string; kind: string; member_a: string | null; member_b: string | null }
    | null;
  if (!conversa?.id) return NextResponse.json({ error: "Conversa nao encontrada." }, { status: 404 });

  const minha =
    conversa.kind === "team"
      ? conversa.member_a === acesso.user.id || conversa.member_b === acesso.user.id
      : acesso.tenantIds.includes(conversa.user_id);
  if (!minha) return NextResponse.json({ error: "Sem permissao." }, { status: 403 });

  /* Mexer so no estagio nao encerra nada: sao duas perguntas diferentes na
     mesma tela. */
  if (mudandoEstagio) {
    if (estagioPedido && !ESTAGIOS.has(estagioPedido)) {
      return NextResponse.json({ error: "Estagio invalido." }, { status: 400 });
    }
    const { error: erroDoEstagio } = await admin
      .from("chat_threads")
      .update({ stage: estagioPedido || null, updated_at: new Date().toISOString() })
      .eq("id", threadId);
    if (erroDoEstagio) return NextResponse.json({ error: erroDoEstagio.message }, { status: 400 });
    return NextResponse.json({ ok: true, estagio: estagioPedido || null });
  }

  /*
    Quem está atendendo.

    Loja com duas pessoas responde a mesma dúvida duas vezes, cada uma com um
    prazo diferente — e o cliente escolhe o que mais gostar. Marcar responsável
    não trava ninguém: é um combinado à vista, e transferir é trocar o nome.
  */
  if (mudandoResponsavel) {
    const responsavel = texto((corpo as { responsavel?: { id?: string; nome?: string } })?.responsavel?.id);
    const nomeDoResponsavel = texto((corpo as { responsavel?: { nome?: string } })?.responsavel?.nome);

    const { error: erroDoResponsavel } = await admin
      .from("chat_threads")
      .update({
        assigned_to: responsavel || null,
        assigned_name: responsavel ? nomeDoResponsavel || null : null,
        updated_at: new Date().toISOString(),
      })
      .eq("id", threadId);

    if (erroDoResponsavel) return NextResponse.json({ error: erroDoResponsavel.message }, { status: 400 });
    return NextResponse.json({ ok: true, responsavel: responsavel || null });
  }

  /* Etiquetas livres: o funil diz em que pé está, a etiqueta diz o que é —
     "urgente", "revenda", "sem pressa". São coisas diferentes. */
  if (mudandoEtiquetas) {
    const lista = Array.isArray(corpo?.etiquetas) ? (corpo?.etiquetas as unknown[]) : [];
    const limpas = [
      ...new Set(
        lista
          .map((etiqueta) => texto(etiqueta).slice(0, 24))
          .filter(Boolean)
      ),
    ].slice(0, 12);

    const { error: erroDasEtiquetas } = await admin
      .from("chat_threads")
      .update({ tags: limpas, updated_at: new Date().toISOString() })
      .eq("id", threadId);

    if (erroDasEtiquetas) return NextResponse.json({ error: erroDasEtiquetas.message }, { status: 400 });
    return NextResponse.json({ ok: true, etiquetas: limpas });
  }

  /*
    Retomar depois.

    A venda de gráfica não morre no "não" — morre no silêncio depois do
    orçamento. Aqui a pessoa marca o dia, e no dia a conversa volta ao topo com
    o sino tocando, em vez de depender de alguém lembrar.
  */
  if (mudandoRetomar) {
    const quando = texto((corpo as { retomarEm?: unknown })?.retomarEm);
    const nota = texto((corpo as { retomarNota?: unknown })?.retomarNota).slice(0, 200);

    if (quando && Number.isNaN(new Date(quando).getTime())) {
      return NextResponse.json({ error: "Data inválida." }, { status: 400 });
    }

    const { error: erroDoLembrete } = await admin
      .from("chat_threads")
      .update({
        follow_up_at: quando || null,
        follow_up_note: quando ? nota || null : null,
        updated_at: new Date().toISOString(),
      })
      .eq("id", threadId);

    if (erroDoLembrete) return NextResponse.json({ error: erroDoLembrete.message }, { status: 400 });
    return NextResponse.json({ ok: true, retomarEm: quando || null });
  }

  const { error } = await admin
    .from("chat_threads")
    .update(
      encerrar
        ? { closed_at: new Date().toISOString(), closed_by: texto(acesso.nome) || "Loja", unread_store: 0 }
        : { closed_at: null, closed_by: null }
    )
    .eq("id", threadId);

  if (error) return NextResponse.json({ error: error.message }, { status: 400 });

  return NextResponse.json({ ok: true, encerrada: encerrar });
}
