import type { SupabaseClient } from "@supabase/supabase-js";

/**
 * O placar do centro de aprendizado, num lugar só.
 *
 * A conta é a mesma na primeira carga da página (servidor) e nas recargas
 * depois de salvar (rota). Duas cópias da conta seriam duas chances de o
 * número mudar sozinho quando a tela atualiza.
 */

export const DIAS_DO_PLACAR = 30;

export type Resumo = {
  no_ar: number;
  rascunhos: number;
  revisar: number;
  secoes: number;
  leituras: number;
  respostas: number;
  resolveu: number | null;
  buscas_sem_resposta: number;
  termos_sem_resposta: number;
};

export type TermoSemResposta = {
  normalizado: string;
  termo: string;
  vezes: number;
  ultima: string;
};

// eslint-disable-next-line @typescript-eslint/no-explicit-any
type Cliente = SupabaseClient<any, "public", any>;

export async function calcularMetricas(admin: Cliente) {
  const desde = new Date(Date.now() - DIAS_DO_PLACAR * 24 * 60 * 60 * 1000).toISOString();

  const [artigos, secoes, leituras, respostas, buscas] = await Promise.all([
    admin.from("help_articles").select("id,status,needs_review"),
    admin.from("help_sections").select("id", { count: "exact", head: true }),
    admin.from("help_article_views").select("id", { count: "exact", head: true }).gte("created_at", desde),
    admin.from("help_article_feedback").select("helpful"),
    admin.from("help_searches").select("term,normalized,created_at").eq("results_count", 0).gte("created_at", desde),
  ]);

  const lista = (artigos.data ?? []) as Array<{ status: string; needs_review: boolean }>;
  const votos = (respostas.data ?? []) as Array<{ helpful: boolean }>;
  const sim = votos.filter((v) => v.helpful).length;

  /* Agrupado pelo termo normalizado, e não pelo que foi digitado: "Nota
     Fiscal" e "nota fiscal" são a mesma dúvida. Separadas, contariam 1 e 1 em
     vez de 2, e a pauta mais pedida apareceria como se fosse rara. */
  const agrupadas = new Map<string, TermoSemResposta>();
  for (const b of (buscas.data ?? []) as Array<{ term: string; normalized: string; created_at: string }>) {
    const atual = agrupadas.get(b.normalized);
    if (atual) {
      atual.vezes += 1;
      if (b.created_at > atual.ultima) atual.ultima = b.created_at;
    } else {
      agrupadas.set(b.normalized, { normalizado: b.normalized, termo: b.term, vezes: 1, ultima: b.created_at });
    }
  }

  const sem_resposta = [...agrupadas.values()]
    .sort((a, b) => b.vezes - a.vezes || (a.termo < b.termo ? -1 : 1))
    .slice(0, 40);

  const resumo: Resumo = {
    no_ar: lista.filter((a) => a.status === "published").length,
    rascunhos: lista.filter((a) => a.status === "draft").length,
    revisar: lista.filter((a) => a.needs_review).length,
    secoes: secoes.count ?? 0,
    leituras: leituras.count ?? 0,
    respostas: votos.length,
    resolveu: votos.length > 0 ? Math.round((sim / votos.length) * 100) : null,
    buscas_sem_resposta: sem_resposta.reduce((soma, b) => soma + b.vezes, 0),
    termos_sem_resposta: sem_resposta.length,
  };

  return { resumo, sem_resposta };
}

/**
 * Leituras de 30 dias e percentual de "resolveu?" por artigo.
 *
 * Vem junto com a listagem porque a tela mostra os dois em cada linha, e uma
 * chamada por artigo seria uma tela que demora em vez de uma tela que abre.
 */
export async function medirArtigos(admin: Cliente) {
  const desde = new Date(Date.now() - DIAS_DO_PLACAR * 24 * 60 * 60 * 1000).toISOString();
  const [{ data: leituras }, { data: respostas }] = await Promise.all([
    admin.from("help_article_views").select("article_id").gte("created_at", desde),
    admin.from("help_article_feedback").select("article_id,helpful"),
  ]);

  const lidos = new Map<string, number>();
  for (const l of (leituras ?? []) as Array<{ article_id: string }>) {
    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 ?? []) as Array<{ article_id: string; helpful: boolean }>) {
    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);
  }

  return (id: string) => {
    const voto = votos.get(id);
    return {
      leituras_30d: lidos.get(id) ?? 0,
      respostas: voto?.total ?? 0,
      /* Nulo, e não zero: "ninguém respondeu ainda" e "todo mundo disse que
         não resolveu" são coisas diferentes na tela. */
      resolveu: voto && voto.total > 0 ? Math.round((voto.sim / voto.total) * 100) : null,
    };
  };
}
