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

/*
  Da conversa para o negócio.

  É aqui que a venda esfriava: o atendente terminava o papo, fechava o Chats,
  abria a tela de cliente, digitava o nome de novo, abria a tela de orçamento,
  procurava o produto de novo — e no meio desse caminho o cliente já tinha
  perguntado em outro lugar.

  Duas ações, um clique cada:

  - virar cliente: o visitante anônimo ganha ficha, e a rota da visita passa a
    morar nela;
  - virar orçamento: nasce um rascunho já com o cliente e com o produto que ele
    estava olhando quando escreveu.

  Nada disso manda nada para o cliente: o orçamento nasce rascunho, para a loja
  conferir o preço antes de enviar. Automatizar o envio seria automatizar o
  erro.
*/

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

/* O que a pessoa digitou como contato pode ser telefone ou e-mail; guardar no
   campo errado é perder o contato na hora de ligar. */
function separarContato(contato: string) {
  const limpo = texto(contato);
  if (!limpo) return { telefone: null as string | null, email: null as string | null };
  if (limpo.includes("@")) return { telefone: null, email: limpo };
  const digitos = limpo.replace(/\D/g, "");
  return { telefone: digitos.length >= 8 ? limpo : null, email: null };
}

export async function POST(request: Request) {
  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
    | { threadId?: unknown; acao?: unknown; produtoId?: unknown }
    | null;

  const threadId = texto(corpo?.threadId);
  const acao = texto(corpo?.acao);
  if (!threadId) return NextResponse.json({ error: "Conversa invalida." }, { status: 400 });

  const admin = createAdminClient();
  const { data } = await admin
    .from("chat_threads")
    .select("id,user_id,kind,client_id,visitor_key,visitor_name,visitor_contact,title")
    .eq("id", threadId)
    .in("user_id", acesso.tenantIds)
    .maybeSingle();

  const conversa = data as
    | {
        id: string;
        user_id: string;
        kind: string;
        client_id: string | null;
        visitor_key: string | null;
        visitor_name: string | null;
        visitor_contact: string | null;
        title: string | null;
      }
    | null;

  if (!conversa?.id) return NextResponse.json({ error: "Conversa nao encontrada." }, { status: 404 });

  /* ---------------- virar cliente ---------------- */

  async function garantirCliente() {
    if (!conversa) return null;
    if (conversa.client_id) return conversa.client_id;

    const nome = texto(conversa.visitor_name) || texto(conversa.title) || "Cliente da loja online";
    const { telefone, email } = separarContato(texto(conversa.visitor_contact));

    const { data: criado, error } = await admin
      .from("clients")
      .insert({
        user_id: conversa.user_id,
        name: nome,
        phone: telefone,
        email,
        origin: "chat",
      })
      .select("id")
      .single();

    if (error || !criado) throw new Error(error?.message || "Nao foi possivel criar o cliente.");
    const clienteId = String((criado as { id: string }).id);

    /* A conversa passa a ter dono, e a rota da visita vai junto para a ficha. */
    await admin.from("chat_threads").update({ client_id: clienteId }).eq("id", conversa.id);
    if (conversa.visitor_key) {
      await admin
        .from("store_visitor_pings")
        .update({ client_id: clienteId })
        .eq("user_id", conversa.user_id)
        .eq("visitor_key", conversa.visitor_key);
    }

    return clienteId;
  }

  if (acao === "cliente") {
    if (conversa.client_id) return NextResponse.json({ ok: true, clienteId: conversa.client_id, jaExistia: true });
    try {
      const clienteId = await garantirCliente();
      return NextResponse.json({ ok: true, clienteId });
    } catch (falha) {
      return NextResponse.json(
        { error: falha instanceof Error ? falha.message : "Nao foi possivel criar o cliente." },
        { status: 400 }
      );
    }
  }

  /* ---------------- virar orçamento ---------------- */

  if (acao !== "orcamento") return NextResponse.json({ error: "Acao desconhecida." }, { status: 400 });

  let clienteId: string | null = null;
  try {
    clienteId = await garantirCliente();
  } catch (falha) {
    return NextResponse.json(
      { error: falha instanceof Error ? falha.message : "Nao foi possivel criar o cliente." },
      { status: 400 }
    );
  }
  if (!clienteId) return NextResponse.json({ error: "Esta conversa não tem cliente." }, { status: 400 });

  /*
    O produto que ele estava olhando.

    Sem isto o orçamento nasce vazio e a pessoa digita tudo de novo — que é
    exatamente o trabalho que este botão existe para poupar.
  */
  let produtoId = texto(corpo?.produtoId) || null;
  if (!produtoId && conversa.visitor_key) {
    const { data: visita } = await admin
      .from("store_visitor_pings")
      .select("product_id")
      .eq("user_id", conversa.user_id)
      .eq("visitor_key", conversa.visitor_key)
      .maybeSingle();
    produtoId = texto((visita as { product_id?: string } | null)?.product_id) || null;
  }

  type ProdutoDoOrcamento = { id: string; name: string; price: number | null };
  let produto: ProdutoDoOrcamento | null = null;
  if (produtoId) {
    const { data: achado } = await admin
      .from("products")
      .select("id,name,price")
      .eq("id", produtoId)
      .eq("user_id", conversa.user_id)
      .maybeSingle();
    produto = (achado as ProdutoDoOrcamento | null) || null;
  }

  const { data: maior } = await admin
    .from("quotes")
    .select("number")
    .eq("user_id", conversa.user_id)
    .order("number", { ascending: false })
    .limit(1)
    .maybeSingle();

  const numero = Math.max(1, Number((maior as { number?: number } | null)?.number || 0) + 1);
  const agora = new Date().toISOString();
  const preco = Number(produto?.price || 0);

  const { data: criado, error: erroDoOrcamento } = await admin
    .from("quotes")
    .insert({
      user_id: conversa.user_id,
      client_id: clienteId,
      number: numero,
      status: "draft",
      title: produto ? produto.name : "Orçamento pelo chat",
      currency: "BRL",
      subtotal: preco,
      total: preco,
      internal_notes: `origem:chat\nchat_thread_id:${conversa.id}`,
      created_by: acesso.user.id,
      created_at: agora,
      updated_at: agora,
    })
    .select("id,number")
    .single();

  if (erroDoOrcamento || !criado) {
    return NextResponse.json(
      { error: erroDoOrcamento?.message || "Nao foi possivel criar o orcamento." },
      { status: 400 }
    );
  }

  const orcamento = criado as { id: string; number: number };

  if (produto) {
    await admin.from("quote_items").insert({
      quote_id: orcamento.id,
      position: 1,
      title: produto.name,
      quantity: 1,
      unit_price: preco,
      line_total: preco,
      product_id: produto.id,
      unit_type: "unit",
    });
  }

  /*
    O registro fica na conversa.

    Daqui a duas semanas ninguém lembra se aquele papo virou orçamento. Uma nota
    interna resolve — e ela não vai para o cliente, que não precisa saber que a
    loja está montando a proposta ainda.
  */
  const recado = `Orçamento #${orcamento.number} criado a partir desta conversa${
    produto ? ` com ${produto.name}` : ""
  }.`;

  await admin.from("chat_messages").insert({
    thread_id: conversa.id,
    user_id: conversa.user_id,
    author_type: "store",
    author_id: acesso.user.id,
    author_name: acesso.nome,
    body: recado,
    internal: true,
    read_by_store_at: agora,
  });

  await avisarConversa([canalDaConversa(conversa.id)], {
    threadId: conversa.id,
    autor: "store",
    autorNome: acesso.nome,
    resumo: "",
  });

  return NextResponse.json({ ok: true, quoteId: orcamento.id, numero: orcamento.number, clienteId });
}
