import { NextResponse } from "next/server";
import { createClient } from "@/lib/supabase-server";
import { createAdminClient } from "@/lib/supabase-admin";
import { isOwnerUser } from "@/lib/owner-auth";
import { faxinarHtmlDoBoletim, faxinarSlug } from "@/lib/faxina-html";
import { CAMPOS_DO_ARTIGO, endereco, limparPalavras, nivel, situacao, texto } from "@/lib/help";

/**
 * Os artigos do centro de aprendizado.
 *
 * O corpo passa pela faxina antes de encostar no banco. A página do help abre
 * sem login: esta rota é a única porta por onde HTML entra, igual à do boletim,
 * e as duas usam a MESMA faxina de propósito — duas peneiras seriam duas
 * chances de esquecer uma delas.
 */

export const dynamic = "force-dynamic";

async function conferirDono() {
  const supabase = await createClient();
  const {
    data: { user },
  } = await supabase.auth.getUser();
  if (!user || !isOwnerUser({ id: user.id, email: user.email })) return null;
  return user;
}

function semPermissao() {
  return NextResponse.json({ error: "Sem permissão." }, { status: 403 });
}

export async function GET(request: Request) {
  if (!(await conferirDono())) return semPermissao();

  const { searchParams } = new URL(request.url);
  const id = texto(searchParams.get("id"));
  const admin = createAdminClient();

  if (id) {
    const { data, error } = await admin.from("help_articles").select(CAMPOS_DO_ARTIGO).eq("id", id).maybeSingle();
    if (error) return NextResponse.json({ error: "Não foi possível carregar o artigo." }, { status: 400 });
    if (!data) return NextResponse.json({ error: "Artigo não encontrado." }, { status: 404 });
    return NextResponse.json({ ok: true, article: data });
  }

  const secao = texto(searchParams.get("section_id"));
  let consulta = admin
    .from("help_articles")
    .select(CAMPOS_DO_ARTIGO)
    .order("position", { ascending: true })
    .order("created_at", { ascending: false });
  if (secao) consulta = consulta.eq("section_id", secao);

  const { data, error } = await consulta;
  if (error) return NextResponse.json({ error: "Não foi possível carregar os artigos." }, { status: 400 });

  /* Leituras dos últimos 30 dias e o percentual de "resolveu?" vêm junto: a
     listagem mostra os dois em cada linha, e uma chamada por artigo seria uma
     tela que demora em vez de uma tela que abre. */
  const trintaDias = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000).toISOString();
  const [{ data: leituras }, { data: respostas }] = await Promise.all([
    admin.from("help_article_views").select("article_id").gte("created_at", trintaDias),
    admin.from("help_article_feedback").select("article_id,helpful"),
  ]);

  const lidos = new Map<string, number>();
  for (const l of leituras ?? []) lidos.set(l.article_id, (lidos.get(l.article_id) ?? 0) + 1);

  const votos = new Map<string, { sim: number; total: number }>();
  for (const r of respostas ?? []) {
    const atual = votos.get(r.article_id) ?? { sim: 0, total: 0 };
    atual.total += 1;
    if (r.helpful) atual.sim += 1;
    votos.set(r.article_id, atual);
  }

  const artigos = (data ?? []).map((a) => {
    const voto = votos.get(a.id);
    return {
      ...a,
      leituras_30d: lidos.get(a.id) ?? 0,
      respostas: voto?.total ?? 0,
      /* Sem resposta nenhuma o campo fica nulo, e não zero: zero por cento e
         "ninguém respondeu ainda" são coisas diferentes na tela. */
      resolveu: voto && voto.total > 0 ? Math.round((voto.sim / voto.total) * 100) : null,
    };
  });

  return NextResponse.json({ ok: true, articles: artigos });
}

export async function POST(request: Request) {
  if (!(await conferirDono())) return semPermissao();

  const body = (await request.json().catch(() => null)) as Record<string, unknown> | null;
  const section_id = texto(body?.section_id);
  if (!section_id) return NextResponse.json({ error: "Escolha uma seção." }, { status: 400 });

  const title = texto(body?.title) || "Sem título";
  const slug = faxinarSlug(texto(body?.slug) || title) || `artigo-${Date.now()}`;
  const estado = situacao(body?.status);

  const admin = createAdminClient();
  const { data: ultimo } = await admin
    .from("help_articles")
    .select("position")
    .eq("section_id", section_id)
    .order("position", { ascending: false })
    .limit(1)
    .maybeSingle();

  const { data, error } = await admin
    .from("help_articles")
    .insert({
      section_id,
      slug,
      title,
      subtitle: texto(body?.subtitle) || null,
      body_html: faxinarHtmlDoBoletim(body?.body_html),
      cover_image_url: endereco(body?.cover_image_url),
      level: nivel(body?.level),
      keywords: limparPalavras(body?.keywords),
      status: estado,
      position: (ultimo?.position ?? 0) + 1,
      published_at: estado === "published" ? new Date().toISOString() : null,
    })
    .select(CAMPOS_DO_ARTIGO)
    .single();

  if (error) {
    const repetido = /duplicate key/i.test(error.message);
    return NextResponse.json(
      { error: repetido ? "Já existe um artigo com esse endereço nesta seção." : "Não foi possível criar o artigo." },
      { status: 400 }
    );
  }
  return NextResponse.json({ ok: true, article: data });
}

export async function PATCH(request: Request) {
  if (!(await conferirDono())) return semPermissao();

  const body = (await request.json().catch(() => null)) as Record<string, unknown> | null;

  if (Array.isArray(body?.order)) {
    const admin = createAdminClient();
    const ids = (body.order as unknown[]).map((v) => texto(v)).filter(Boolean);
    for (let i = 0; i < ids.length; i += 1) {
      await admin.from("help_articles").update({ position: i }).eq("id", ids[i]);
    }
    return NextResponse.json({ ok: true, reordenados: ids.length });
  }

  const id = texto(body?.id);
  if (!id) return NextResponse.json({ error: "Sem artigo." }, { status: 400 });

  const admin = createAdminClient();
  const { data: atual } = await admin.from("help_articles").select("status,published_at").eq("id", id).maybeSingle();
  if (!atual) return NextResponse.json({ error: "Artigo não encontrado." }, { status: 404 });

  const mudanca: Record<string, unknown> = {};
  if (body?.section_id !== undefined) mudanca.section_id = texto(body.section_id);
  if (body?.title !== undefined) mudanca.title = texto(body.title) || "Sem título";
  if (body?.subtitle !== undefined) mudanca.subtitle = texto(body.subtitle) || null;
  if (body?.body_html !== undefined) mudanca.body_html = faxinarHtmlDoBoletim(body.body_html);
  if (body?.cover_image_url !== undefined) mudanca.cover_image_url = endereco(body.cover_image_url);
  if (body?.level !== undefined) mudanca.level = nivel(body.level);
  if (body?.keywords !== undefined) mudanca.keywords = limparPalavras(body.keywords);
  if (body?.needs_review !== undefined) mudanca.needs_review = Boolean(body.needs_review);

  if (body?.slug !== undefined) {
    const slug = faxinarSlug(body.slug);
    if (!slug) return NextResponse.json({ error: "Endereço inválido." }, { status: 400 });
    mudanca.slug = slug;
  }

  if (body?.status !== undefined) {
    const estado = situacao(body.status);
    mudanca.status = estado;
    /* A data de publicação é carimbada UMA vez. Republicar não reescreve a
       data original: quem lê quer saber quando o artigo nasceu, não quando o
       botão foi clicado de novo. */
    if (estado === "published" && !atual.published_at) mudanca.published_at = new Date().toISOString();
    /* Publicar de novo limpa o aviso de revisão: o dono acabou de olhar. */
    if (estado === "published") mudanca.needs_review = Boolean(body?.needs_review);
  }

  if (Object.keys(mudanca).length === 0) return NextResponse.json({ ok: true });

  const { data, error } = await admin
    .from("help_articles")
    .update(mudanca)
    .eq("id", id)
    .select(CAMPOS_DO_ARTIGO)
    .single();

  if (error) {
    const repetido = /duplicate key/i.test(error.message);
    return NextResponse.json(
      { error: repetido ? "Já existe um artigo com esse endereço nesta seção." : "Não foi possível salvar o artigo." },
      { status: 400 }
    );
  }
  return NextResponse.json({ ok: true, article: data });
}

export async function DELETE(request: Request) {
  if (!(await conferirDono())) return semPermissao();

  const { searchParams } = new URL(request.url);
  const id = texto(searchParams.get("id"));
  if (!id) return NextResponse.json({ error: "Sem artigo." }, { status: 400 });

  const admin = createAdminClient();
  const { error } = await admin.from("help_articles").delete().eq("id", id);
  if (error) return NextResponse.json({ error: "Não foi possível apagar o artigo." }, { status: 400 });
  return NextResponse.json({ ok: true });
}
