import { getSupabaseClient } from "@/lib/supabase";

/*
 * O lado social da comunidade de modelos (migration 228): gostei / não gostei,
 * favoritos (o coração) e seguir quem publica. Tudo da pessoa logada; os
 * números (gostei, não gostei, salvos) vêm da contagem pública e o perfil do
 * autor da função resumo_do_autor_da_comunidade.
 *
 * A chave do modelo: o id para os da comunidade; "casa:<chave>" para os da
 * casa. Sem a migration aplicada, tudo responde vazio e os botões somem.
 */

export const chaveDaCasa = (modelo: string) => `casa:${modelo}`;
export type Contagem = { gostei: number; nao_gostei: number; salvos: number };
export const CONTAGEM_VAZIA: Contagem = { gostei: 0, nao_gostei: 0, salvos: 0 };
export type ResumoDoAutor = { modelos: number; seguidores: number; gostei: number; usos: number; sigo: boolean };

export class SocialIndisponivel extends Error {}
const faltaATabela = (erro: { code?: string; message?: string } | null) => Boolean(erro && (erro.code === "42P01" || erro.code === "PGRST205" || erro.code === "PGRST202" || /modelos_reacoes|modelos_favoritos|comunidade_seguidores|modelos_curtidas_contagem|resumo_do_autor/.test(erro.message || "")));

async function quem() {
  const {
    data: { user },
  } = await getSupabaseClient().auth.getUser();
  return user?.id ?? null;
}

/** O que a pessoa já fez (votos e favoritos) e se o lado social está ligado no banco. */
export async function meuEstado(): Promise<{ ligado: boolean; votos: Map<string, 1 | -1>; favoritos: Set<string> }> {
  const supabase = getSupabaseClient();
  const [votos, favoritos] = await Promise.all([supabase.from("modelos_reacoes").select("modelo,valor").limit(2000), supabase.from("modelos_favoritos").select("modelo,created_at").order("created_at", { ascending: false }).limit(2000)]);
  if (faltaATabela(votos.error) || faltaATabela(favoritos.error)) return { ligado: false, votos: new Map(), favoritos: new Set() };
  return {
    ligado: true,
    votos: new Map(((votos.data || []) as Array<{ modelo: string; valor: number }>).map((v) => [v.modelo, v.valor === 1 ? 1 : -1])),
    favoritos: new Set(((favoritos.data || []) as Array<{ modelo: string }>).map((f) => f.modelo)),
  };
}

/** Os números de um modelo. */
export async function contagemDo(modelo: string): Promise<Contagem> {
  const { data, error } = await getSupabaseClient().from("modelos_curtidas_contagem").select("gostei,nao_gostei,salvos").eq("modelo", modelo).maybeSingle();
  if (error || !data) return CONTAGEM_VAZIA;
  return data as Contagem;
}

/** Gostei (1), não gostei (-1) ou tirar o voto (0). */
export async function votar(modelo: string, valor: 1 | -1 | 0) {
  const supabase = getSupabaseClient();
  const usuario = await quem();
  if (!usuario) throw new Error("Entre no painel de novo.");
  const { error } = valor === 0 ? await supabase.from("modelos_reacoes").delete().eq("modelo", modelo).eq("usuario", usuario) : await supabase.from("modelos_reacoes").upsert({ modelo, usuario, valor }, { onConflict: "modelo,usuario" });
  if (faltaATabela(error)) throw new SocialIndisponivel("As curtidas ainda não foram ligadas.");
  if (error) throw new Error("Não deu para registrar agora.");
}

export async function favoritar(modelo: string, salvar: boolean) {
  const supabase = getSupabaseClient();
  const usuario = await quem();
  if (!usuario) throw new Error("Entre no painel de novo.");
  const { error } = salvar ? await supabase.from("modelos_favoritos").upsert({ modelo, usuario }, { onConflict: "modelo,usuario", ignoreDuplicates: true }) : await supabase.from("modelos_favoritos").delete().eq("modelo", modelo).eq("usuario", usuario);
  if (faltaATabela(error)) throw new SocialIndisponivel("Os favoritos ainda não foram ligados.");
  if (error) throw new Error("Não deu para salvar agora.");
}

/** O perfil de quem publica (modelos na galeria, seguidores, curtidas, usos e se eu sigo). */
export async function resumoDoAutor(autor: string): Promise<ResumoDoAutor | null> {
  const { data, error } = await getSupabaseClient().rpc("resumo_do_autor_da_comunidade", { p_autor: autor });
  if (error) return null;
  const linha = (Array.isArray(data) ? data[0] : data) as ResumoDoAutor | undefined;
  return linha ?? null;
}

export async function seguir(autor: string, sim: boolean) {
  const supabase = getSupabaseClient();
  const usuario = await quem();
  if (!usuario) throw new Error("Entre no painel de novo.");
  const { error } = sim ? await supabase.from("comunidade_seguidores").upsert({ autor, usuario }, { onConflict: "autor,usuario", ignoreDuplicates: true }) : await supabase.from("comunidade_seguidores").delete().eq("autor", autor).eq("usuario", usuario);
  if (faltaATabela(error)) throw new SocialIndisponivel("Seguir ainda não foi ligado.");
  if (error) throw new Error("Não deu para seguir agora.");
}
