import { cookies } from "next/headers";
import { NextResponse } from "next/server";
import { avisarConversa, avisarMovimento, canalDaConversa } from "@/lib/chats-aviso";
import { createAdminClient } from "@/lib/supabase-admin";

/*
  Sinal de vida de quem esta na loja.

  A cada tantos segundos a aba aberta diz "ainda estou aqui, olhando isto". E o
  que permite a loja ver o movimento — e falar com quem esta na frente da
  vitrine, em vez de descobrir a visita semanas depois num relatorio.

  Quando a pessoa muda de pagina, coloca algo no carrinho ou abre o checkout, o
  sinal vem na hora e com nome: isso vira um passo da rota dela, guardado para
  a loja entender de onde veio a duvida antes de responder.

  Tambem e daqui que sai o "posso ajudar?": quando a pessoa ja passou tempo
  suficiente na loja e a loja configurou uma saudacao, a conversa comeca
  sozinha.
*/

const COOKIE_DO_VISITANTE = "ktl_visitante";
const SAUDACAO_PADRAO = "Oi! Vi que você está por aqui. Se precisar de ajuda com algum produto, é só chamar.";

const DIAS_DE_MEMORIA = 30;
/* Meia hora sem nenhum sinal e outra visita; menos que isso e a mesma pessoa
   trocando de aba ou recarregando. */
const VISITA_CONTINUA_MS = 30 * 60 * 1000;

/* Passos que a loja entende. Qualquer outra coisa e so sinal de vida. */
const PASSOS = new Set(["entrou", "pagina", "produto", "busca", "carrinho", "checkout", "compra"]);

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

function numero(valor: unknown) {
  const convertido = Number(valor);
  return Number.isFinite(convertido) ? convertido : null;
}

function chaveValida(chave: string) {
  return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(chave);
}

async function chaveDaVez(informada: string) {
  if (chaveValida(informada)) return informada;
  const cookieStore = await cookies();
  const doCookie = texto(cookieStore.get(COOKIE_DO_VISITANTE)?.value);
  return chaveValida(doCookie) ? doCookie : "";
}

/* De onde a pessoa veio, em nome de gente: "Instagram" diz mais do que a URL
   inteira com os codigos de campanha. */
function origemLegivel(bruta: string) {
  if (!bruta) return null;
  try {
    const casa = new URL(bruta).hostname.replace(/^www\./, "");
    if (/instagram/.test(casa)) return "Instagram";
    if (/facebook|fb\.com/.test(casa)) return "Facebook";
    if (/google/.test(casa)) return "Google";
    if (/bing|duckduckgo|yahoo/.test(casa)) return "Busca";
    if (/whatsapp|wa\.me/.test(casa)) return "WhatsApp";
    if (/tiktok/.test(casa)) return "TikTok";
    if (/youtube|youtu\.be/.test(casa)) return "YouTube";
    if (/t\.co|twitter|x\.com/.test(casa)) return "X";
    if (/linkedin/.test(casa)) return "LinkedIn";
    return casa;
  } catch {
    return null;
  }
}

export async function POST(request: Request) {
  const corpo = (await request.json().catch(() => null)) as
    | {
        slug?: unknown;
        chave?: unknown;
        caminho?: unknown;
        titulo?: unknown;
        produtoId?: unknown;
        produtoNome?: unknown;
        produtoPreco?: unknown;
        produtoImagem?: unknown;
        origem?: unknown;
        busca?: unknown;
        carrinhoItens?: unknown;
        carrinhoTotal?: unknown;
        passo?: unknown;
      }
    | null;

  const slug = texto(corpo?.slug);
  const chave = await chaveDaVez(texto(corpo?.chave));
  if (!slug || !chave) return NextResponse.json({ ok: true, ignorado: true });

  const admin = createAdminClient();
  const { data } = await admin
    .from("profiles")
    .select(
      "id,store_chat_enabled,store_chat_welcome,store_chat_welcome_enabled,store_name,catalog_name,chat_welcome_delay,chat_welcome_trigger"
    )
    .eq("slug", slug)
    .maybeSingle();

  const loja = data as
    | {
        id: string;
        store_chat_enabled?: boolean;
        store_chat_welcome?: string | null;
        store_chat_welcome_enabled?: boolean;
        store_name?: string | null;
        catalog_name?: string | null;
        chat_welcome_delay?: number | null;
        chat_welcome_trigger?: string | null;
      }
    | null;

  /* Sem chat ligado a loja nao vai atender ninguem: nao ha por que guardar a
     presenca. */
  if (!loja?.id || loja.store_chat_enabled !== true) return NextResponse.json({ ok: true, ignorado: true });

  const agora = new Date().toISOString();
  const produtoId = texto(corpo?.produtoId);
  const preco = numero(corpo?.produtoPreco);
  let passo = texto(corpo?.passo);
  const carrinhoItens = numero(corpo?.carrinhoItens);
  const carrinhoTotal = numero(corpo?.carrinhoTotal);
  const origem = origemLegivel(texto(corpo?.origem));

  const { data: existente } = await admin
    .from("store_visitor_pings")
    .select("id,pings,thread_id,welcomed_at,visitor_name,referrer,last_seen_at,first_seen_at")
    .eq("user_id", loja.id)
    .eq("visitor_key", chave)
    .maybeSingle();

  const registro = existente as
    | {
        id: string;
        pings: number;
        thread_id: string | null;
        welcomed_at: string | null;
        visitor_name: string | null;
        referrer: string | null;
        last_seen_at: string | null;
        first_seen_at: string | null;
      }
    | null;

  /*
    "Entrou na loja" e uma vez por visita.

    A aba recem-aberta sempre acha que esta chegando — e ela esta, do ponto de
    vista dela. Mas recarregar a pagina ou abrir um produto em outra aba nao e
    uma entrada nova, e a linha do tempo ficaria repetindo "entrou" a cada
    clique. Quem sabe a verdade e o servidor: se aquele navegador deu sinal
    agora ha pouco, ele nunca saiu.
  */
  const visitaEmAndamento =
    Boolean(registro?.last_seen_at) &&
    Date.now() - new Date(String(registro?.last_seen_at)).getTime() < VISITA_CONTINUA_MS;
  if (passo === "entrou" && visitaEmAndamento) {
    passo = produtoId ? "produto" : "pagina";
  }

  const campos = {
    user_id: loja.id,
    visitor_key: chave,
    page_path: texto(corpo?.caminho).slice(0, 300) || null,
    page_title: texto(corpo?.titulo).slice(0, 160) || null,
    product_id: produtoId && /^[0-9a-f-]{36}$/i.test(produtoId) ? produtoId : null,
    product_name: texto(corpo?.produtoNome).slice(0, 160) || null,
    product_price: preco && preco > 0 ? preco : null,
    product_image: texto(corpo?.produtoImagem).slice(0, 600) || null,
    cart_items: carrinhoItens && carrinhoItens > 0 ? Math.round(carrinhoItens) : 0,
    cart_total: carrinhoTotal && carrinhoTotal > 0 ? carrinhoTotal : 0,
    last_seen_at: agora,
  };

  if (registro?.id) {
    await admin
      .from("store_visitor_pings")
      .update({
        ...campos,
        pings: Number(registro.pings || 0) + 1,
        /* A origem e a da chegada: nao se sobrescreve com a pagina anterior da
           propria loja a cada passo. */
        ...(registro.referrer ? {} : origem ? { referrer: origem } : {}),
      })
      .eq("id", registro.id);
  } else {
    await admin
      .from("store_visitor_pings")
      .insert({ ...campos, first_seen_at: agora, pings: 1, referrer: origem });
  }

  /*
    Um passo da rota.

    So entra aqui o que a pessoa fez de proposito — trocou de pagina, buscou,
    mexeu no carrinho. O sinal de vida de 25 em 25 segundos nao vira linha, ou
    a rota viraria um carimbo de ponto ilegivel.
  */
  if (PASSOS.has(passo)) {
    await admin.from("store_visitor_events").insert({
      user_id: loja.id,
      visitor_key: chave,
      kind: passo,
      page_path: campos.page_path,
      title: campos.page_title,
      product_id: campos.product_id,
      product_name: campos.product_name,
      product_image: campos.product_image,
      product_price: campos.product_price,
      quantity: passo === "carrinho" ? campos.cart_items : null,
      amount: passo === "carrinho" || passo === "checkout" ? campos.cart_total : null,
      detail: passo === "busca" ? texto(corpo?.busca).slice(0, 160) || null : origem,
      created_at: agora,
    });

    await avisarMovimento(loja.id, {
      chave,
      tipo: passo,
      produto: campos.product_name,
      pagina: campos.page_title || campos.page_path,
    });

    /*
      Faxina.

      Navegacao de dois meses atras nao ajuda a vender nada e so engorda a
      tabela. Em vez de mais uma tarefa agendada para alguem esquecer, a
      limpeza pega carona: de vez em quando um passo qualquer varre o que
      passou de 30 dias.
    */
    if (Math.random() < 0.01) {
      const limite = new Date(Date.now() - DIAS_DE_MEMORIA * 24 * 60 * 60 * 1000).toISOString();
      await admin.from("store_visitor_events").delete().lt("created_at", limite);
    }
  }

  /*
    Saudacao automatica.

    Nao no primeiro segundo — quem acabou de abrir a pagina ainda esta se
    situando, e um "posso ajudar?" imediato parece armadilha.

    A hora de falar e da loja: por tempo (quantos segundos a pessoa ja esta ali)
    ou por acao (so quando ela abre um produto, busca ou mexe no carrinho — que
    e quando ha o que perguntar). Quem vende caneca fala cedo; quem vende
    projeto deixa a pessoa ler.
  */
  const segundosNaLoja = registro?.first_seen_at
    ? (Date.now() - new Date(registro.first_seen_at).getTime()) / 1000
    : 0;
  const esperaDaLoja = Math.max(0, Number(loja.chat_welcome_delay ?? 25));
  const porAcao = texto(loja.chat_welcome_trigger) === "acao";

  const naHora = porAcao
    ? passo === "produto" || passo === "busca" || passo === "carrinho" || passo === "checkout"
    : segundosNaLoja >= esperaDaLoja;

  const deveSaudar =
    loja.store_chat_welcome_enabled === true && naHora && !registro?.welcomed_at && !registro?.thread_id;

  if (!deveSaudar) return NextResponse.json({ ok: true });

  const nomeDoVisitante = texto(registro?.visitor_name) || "Visitante";
  const saudacao = texto(loja.store_chat_welcome) || SAUDACAO_PADRAO;

  const { data: conversaCriada } = await admin
    .from("chat_threads")
    .insert({
      user_id: loja.id,
      kind: "visitor",
      visitor_key: chave,
      visitor_name: nomeDoVisitante,
      title: nomeDoVisitante,
      first_seen_at: agora,
      last_seen_at: agora,
    })
    .select("id")
    .single();

  /* Se a conversa ja existia (a pessoa falou antes), a saudacao nao faz mais
     sentido: seria a loja se apresentando no meio do papo. */
  let threadId = (conversaCriada as { id?: string } | null)?.id || null;
  if (!threadId) {
    const { data: jaExistia } = await admin
      .from("chat_threads")
      .select("id")
      .eq("kind", "visitor")
      .eq("user_id", loja.id)
      .eq("visitor_key", chave)
      .maybeSingle();
    threadId = (jaExistia as { id?: string } | null)?.id || null;
    if (threadId) {
      await admin
        .from("store_visitor_pings")
        .update({ thread_id: threadId, welcomed_at: agora })
        .eq("user_id", loja.id)
        .eq("visitor_key", chave);
      return NextResponse.json({ ok: true });
    }
    return NextResponse.json({ ok: true });
  }

  const nomeDaLoja = texto(loja.catalog_name) || texto(loja.store_name) || "Loja";
  await admin.from("chat_messages").insert({
    thread_id: threadId,
    user_id: loja.id,
    author_type: "store",
    author_name: nomeDaLoja,
    body: saudacao,
    read_by_store_at: agora,
  });

  await admin
    .from("chat_threads")
    .update({
      last_message_at: agora,
      last_message_preview: saudacao.slice(0, 120),
      last_message_author: "store",
      updated_at: agora,
      unread_other: 1,
    })
    .eq("id", threadId);

  await admin
    .from("store_visitor_pings")
    .update({ thread_id: threadId, welcomed_at: agora })
    .eq("user_id", loja.id)
    .eq("visitor_key", chave);

  /* O balao do visitante acende sozinho. O sino da loja fica quieto: quem
     falou foi a propria loja, e avisar alguem da propria fala e ruido. */
  await avisarConversa([canalDaConversa(threadId), `visitante-${chave}`], {
    threadId,
    autor: "store",
    autorNome: nomeDaLoja,
    resumo: saudacao.slice(0, 120),
  });

  return NextResponse.json({ ok: true, saudou: true, threadId });
}
