import { createAdminClient } from "@/lib/supabase-admin";
import { lembrar } from "@/lib/lembranca";
import {
  COLUNAS_DO_CUPOM_DO_WIDGET,
  DIAS_DOS_MAIS_VENDIDOS,
  dadosPedidos,
  montarEndereco,
  telefoneLegivel,
  type ComboDaLoja,
  type CupomDaLoja,
  type DadosDosWidgets,
  type LiveDaLoja,
  type PontoDeRetirada,
} from "@/lib/widgets-da-home";

/**
 * O que os blocos novos da página inicial leem do banco: cupons, lives,
 * mais vendidos, combos e pontos de retirada.
 *
 * Só sai do banco o que as seções da loja usam (loja sem esses blocos não
 * lê nada a mais: a função devolve null e a página fica como sempre). Fica
 * lembrado dois minutos, como o resto da loja (o aviso do admin apaga tudo
 * da loja de uma vez, a chave começa pelo slug). O editor da página inicial
 * lê tudo, agora, para o lojista ver qualquer bloco que puser no rascunho.
 *
 * Nada aqui é dado de cliente: mais vendidos devolve só o id do produto e a
 * soma, das vendas da própria loja (migration 198).
 */

// eslint-disable-next-line @typescript-eslint/no-explicit-any
type Linha = any;

type Pedido = ReturnType<typeof dadosPedidos>;

async function buscar(perfil: Linha, pedido: Pedido): Promise<Omit<DadosDosWidgets, "agora" | "semPreco">> {
  const supabase = createAdminClient();
  const dono = String(perfil.id);

  const vazio = Promise.resolve({ data: [] as Linha[], error: null });
  const [cupons, lives, combos, retiradas, ...vendidos] = await Promise.all([
    pedido.cupons
      ? supabase
          .from("catalog_coupons")
          .select(COLUNAS_DO_CUPOM_DO_WIDGET)
          .eq("user_id", dono)
          .eq("active", true)
          .order("created_at", { ascending: false })
          .limit(60)
      : vazio,
    pedido.lives
      ? supabase
          .from("live_salas")
          .select("id,titulo,comeca_em,duracao_min,espera_min,status,iniciada_em,categoria,product_id")
          .eq("user_id", dono)
          .eq("vitrine", true)
          .in("status", ["agendada", "ao_vivo"])
          /* Live de venda (a reunião nunca vai para a vitrine). */
          .or("categoria.is.null,categoria.eq.venda")
          .gte("comeca_em", new Date(Date.now() - 12 * 60 * 60 * 1000).toISOString())
          .order("comeca_em", { ascending: true })
          .limit(6)
      : vazio,
    pedido.combos
      ? supabase
          .from("product_combos")
          .select("id,title,discount_type,discount_value,main_product_id,combo_product_id")
          .eq("user_id", dono)
          .eq("active", true)
          .order("created_at", { ascending: false })
          .limit(80)
      : vazio,
    pedido.local
      ? supabase
          .from("catalog_pickup_locations")
          .select("name,street,number,complement,neighborhood,city,state,zip,instructions,position")
          .eq("user_id", dono)
          .eq("active", true)
          .order("position", { ascending: true })
          .limit(8)
      : vazio,
    ...pedido.maisVendidos.map((dias) => supabase.rpc("mais_vendidos_da_loja", { p_dono: dono, p_dias: dias, p_limite: 24 })),
  ]);

  /* A capa da live é a foto do produto dela, como na vitrine das lives. */
  const salas = (Array.isArray(lives.data) ? lives.data : []) as Linha[];
  const produtosDasLives = salas.map((s) => s.product_id).filter(Boolean) as string[];
  const capas = new Map<string, string | null>();
  if (produtosDasLives.length) {
    const { data } = await supabase.from("products").select("id,image_url").in("id", produtosDasLives).eq("user_id", dono);
    for (const p of (data ?? []) as Array<{ id: string; image_url: string | null }>) capas.set(p.id, p.image_url);
  }

  const maisVendidos: DadosDosWidgets["maisVendidos"] = {};
  pedido.maisVendidos.forEach((dias, indice) => {
    const resposta = vendidos[indice] as { data?: unknown; error?: unknown } | undefined;
    const linhas = Array.isArray(resposta?.data) ? (resposta?.data as Array<{ product_id: string }>) : [];
    maisVendidos[String(dias) as "7" | "30" | "90"] = linhas.map((l) => String(l.product_id));
  });

  return {
    cupons: ((Array.isArray(cupons.data) ? cupons.data : []) as Linha[]).map(
      (c): CupomDaLoja => ({
        id: String(c.id),
        code: String(c.code || ""),
        type: String(c.type || ""),
        value: Number(c.value) || 0,
        min_total: c.min_total === null || c.min_total === undefined ? null : Number(c.min_total),
        min_items: c.min_items === null || c.min_items === undefined ? null : Number(c.min_items),
        active: c.active !== false,
        starts_at: c.starts_at ?? null,
        ends_at: c.ends_at ?? null,
      })
    ),
    corte: {
      ligado: perfil.production_cutoff_enabled === true && Boolean(perfil.production_cutoff_time),
      hora: perfil.production_cutoff_time ? String(perfil.production_cutoff_time) : null,
    },
    lives: salas.map(
      (s): LiveDaLoja => ({
        id: String(s.id),
        titulo: String(s.titulo || "Live"),
        comeca_em: String(s.comeca_em),
        duracao_min: Number(s.duracao_min) || 60,
        espera_min: Number(s.espera_min) || 0,
        status: s.status,
        iniciada_em: s.iniciada_em ?? null,
        categoria: s.categoria ?? null,
        capa: s.product_id ? capas.get(String(s.product_id)) ?? null : null,
      })
    ),
    maisVendidos,
    combos: ((Array.isArray(combos.data) ? combos.data : []) as Linha[]).map(
      (c): ComboDaLoja => ({
        id: String(c.id),
        title: c.title ?? null,
        discount_type: String(c.discount_type || "none"),
        discount_value: Number(c.discount_value) || 0,
        main_product_id: String(c.main_product_id),
        combo_product_id: String(c.combo_product_id),
      })
    ),
    local: {
      endereco: montarEndereco({
        rua: perfil.address_street,
        numero: perfil.address_number,
        complemento: perfil.address_complement,
        bairro: perfil.address_neighborhood,
        cidade: perfil.address_city,
        estado: perfil.address_state,
        cep: perfil.address_zip,
      }) ?? (perfil.catalog_footer_address || perfil.address
        ? { linhas: [String(perfil.catalog_footer_address || perfil.address).trim()], busca: String(perfil.catalog_footer_address || perfil.address).trim() }
        : null),
      retiradas: ((Array.isArray(retiradas.data) ? retiradas.data : []) as Linha[])
        .map((r): PontoDeRetirada | null => {
          const endereco = montarEndereco({ rua: r.street, numero: r.number, complemento: r.complement, bairro: r.neighborhood, cidade: r.city, estado: r.state, cep: r.zip });
          return endereco ? { nome: String(r.name || "Retirada"), endereco, instrucoes: String(r.instructions || "").trim().slice(0, 300) } : null;
        })
        .filter((r): r is PontoDeRetirada => Boolean(r)),
      telefone: telefoneLegivel(perfil.company_whatsapp || perfil.whatsapp || perfil.company_phone || perfil.phone || "") || null,
    },
  };
}

/**
 * Os dados dos blocos para as seções que a página vai desenhar. Sem bloco
 * que precise de banco: null (nada é lido, a página não muda).
 */
export async function carregarDadosDosWidgets(
  perfil: Linha,
  secoes: Array<{ config?: unknown }>,
  opcoes: { noEditor: boolean; semPreco: boolean }
): Promise<DadosDosWidgets | null> {
  const slug = String(perfil?.slug || "").toLowerCase();
  if (!perfil?.id || !slug) return null;
  const usados = secoes.some((s) => {
    const modo = s?.config && typeof s.config === "object" ? (s.config as Record<string, unknown>).mode : null;
    return typeof modo === "string" && WIDGETS_COM_DADOS.has(modo);
  });
  if (!usados && !opcoes.noEditor) return null;

  const pedido: Pedido = opcoes.noEditor
    ? { cupons: true, lives: true, combos: true, local: true, maisVendidos: [...DIAS_DOS_MAIS_VENDIDOS] }
    : dadosPedidos(secoes);
  const chave = `${slug}/widgets/${[pedido.cupons ? "c" : "", pedido.lives ? "l" : "", pedido.combos ? "k" : "", pedido.local ? "e" : "", pedido.maisVendidos.join("-")].join(".")}`;
  try {
    const lidos = opcoes.noEditor ? await buscar(perfil, pedido) : await lembrar(chave, () => buscar(perfil, pedido));
    return { ...lidos, agora: Date.now(), semPreco: opcoes.semPreco };
  } catch {
    /* Um bloco sem dados some sozinho; a página nunca cai por causa dele. */
    return null;
  }
}

/* Os tipos que pedem algo do banco ou do perfil (os outros se viram com a
   configuração e os produtos que a página já tem). */
const WIDGETS_COM_DADOS = new Set(["coupon_highlight", "order_cutoff", "next_live", "auto_list", "combo_highlight", "store_location", "flash_offer"]);
