import { NextResponse } from "next/server";
import { createClient } from "@supabase/supabase-js";

/**
 * A busca do centro de aprendizado, e o registro do que não achou.
 *
 * A busca em si podia rodar com a chave anônima. Ela roda com a de serviço
 * porque a MESMA chamada grava o termo e quantos resultados deu — e escrita
 * pelo navegador está fechada de propósito, para o mundo não poder encher a
 * tabela de lixo.
 */

export const runtime = "nodejs";
export const dynamic = "force-dynamic";

const LIMITE = 8;

function normalizar(entrada: string) {
  return entrada
    .toLowerCase()
    .normalize("NFD")
    .replace(/[\u0300-\u036f]/g, "")
    .replace(/\s+/g, " ")
    .trim();
}

function servico() {
  return createClient(
    process.env.NEXT_PUBLIC_SUPABASE_URL as string,
    process.env.SUPABASE_SERVICE_ROLE_KEY as string,
    { auth: { persistSession: false, autoRefreshToken: false } }
  );
}

export async function GET(request: Request) {
  const { searchParams } = new URL(request.url);
  const termo = String(searchParams.get("q") || "").trim().slice(0, 120);
  if (termo.length < 2) return NextResponse.json({ ok: true, results: [] });

  const normalizado = normalizar(termo);
  const admin = servico();

  const [{ data: artigos }, { data: secoes }] = await Promise.all([
    admin
      .from("help_articles")
      .select("slug,title,subtitle,keywords,section_id")
      .eq("status", "published")
      .limit(400),
    admin.from("help_sections").select("id,slug,title").eq("active", true),
  ]);

  const porId = new Map((secoes ?? []).map((s) => [s.id, s]));

  /* A busca é feita aqui, e não no banco, porque o acervo é pequeno (centenas
     de artigos) e porque assim ela entende acento: "orcamento" acha
     "Orçamento". Um `ilike` no Postgres não acharia sem uma coluna
     normalizada, e essa coluna teria de ser mantida em dia a cada gravação. */
  const palavras = normalizado.split(" ").filter(Boolean);
  const pontuados = (artigos ?? [])
    .map((a) => {
      const secao = porId.get(a.section_id);
      if (!secao) return null;
      const titulo = normalizar(String(a.title || ""));
      const apoio = normalizar(String(a.subtitle || ""));
      const chaves = ((a.keywords ?? []) as string[]).map((k) => normalizar(k));
      let ponto = 0;
      for (const p of palavras) {
        if (titulo.includes(p)) ponto += titulo.startsWith(p) ? 6 : 4;
        if (chaves.some((k) => k.includes(p))) ponto += 3;
        if (apoio.includes(p)) ponto += 1;
      }
      return ponto > 0
        ? {
            ponto,
            slug: String(a.slug),
            title: String(a.title),
            subtitle: (a.subtitle as string | null) ?? null,
            secao: String(secao.slug),
            secao_titulo: String(secao.title),
          }
        : null;
    })
    .filter((x): x is NonNullable<typeof x> => x !== null)
    .sort((a, b) => b.ponto - a.ponto)
    .slice(0, LIMITE);

  /* Grava e segue: se o registro falhar, a busca não pode falhar junto. */
  void admin
    .from("help_searches")
    .insert({ term: termo, normalized: normalizado, results_count: pontuados.length })
    .then(() => undefined, () => undefined);

  /* O peso da busca fica aqui dentro: a tela mostra a ordem, não a nota. */
  return NextResponse.json({
    ok: true,
    results: pontuados.map((p) => ({
      slug: p.slug,
      title: p.title,
      subtitle: p.subtitle,
      secao: p.secao,
      secao_titulo: p.secao_titulo,
    })),
  });
}
