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

import { baseDaLojaSemPedido } from "@/lib/digitais/fila-regras";
import { montarEmailDaLoja } from "@/lib/digitais/servidor/email-da-loja";
import { criarLinkDaEntrega, type MontagemDaEntrega } from "@/lib/digitais/servidor/entrega";
import { lerLojaDosDigitais } from "@/lib/digitais/servidor/loja";

/*
 * Os lembretes da live: 1 dia antes e 15 minutos antes, para quem garantiu a
 * vaga. A varredura (a cada minuto, na fila dos digitais) marca a live antes
 * de pôr os e-mails na fila: cada lembrete sai uma vez só, mesmo com dois
 * servidores rodando.
 */

type Admin = SupabaseClient;
export type QuandoDoLembrete = "dia" | "15";

type SalaParaLembrar = { id: string; user_id: string; product_id: string | null; titulo: string; comeca_em: string };

async function salasNaJanela(admin: Admin, quando: QuandoDoLembrete, lojas: string[] | null): Promise<SalaParaLembrar[]> {
  const agora = Date.now();
  const coluna = quando === "dia" ? "lembrete_dia_em" : "lembrete_15_em";
  /* "1 dia antes": entre 2 h e 24 h antes (live marcada em cima da hora ganha o aviso do dia também).
     "15 min": entre 16 min antes e 5 min depois do horário. */
  const de = quando === "dia" ? new Date(agora + 2 * 3600000) : new Date(agora - 5 * 60000);
  const ate = quando === "dia" ? new Date(agora + 24 * 3600000) : new Date(agora + 16 * 60000);
  let consulta = admin
    .from("live_salas")
    .select("id,user_id,product_id,titulo,comeca_em")
    .eq("status", "agendada")
    .is(coluna, null)
    .not("product_id", "is", null)
    .gte("comeca_em", de.toISOString())
    .lte("comeca_em", ate.toISOString())
    .limit(50);
  if (lojas) consulta = consulta.in("user_id", lojas);
  const { data } = await consulta;
  return (data ?? []) as SalaParaLembrar[];
}

/* Varre as lives que pedem lembrete agora e põe os e-mails na fila. */
export async function agendarLembretesDasLives(admin: Admin, lojas: string[] | null): Promise<number> {
  let postos = 0;
  for (const quando of ["15", "dia"] as const) {
    const coluna = quando === "dia" ? "lembrete_dia_em" : "lembrete_15_em";
    for (const sala of await salasNaJanela(admin, quando, lojas)) {
      /* Marca primeiro: quem marcar é quem manda. */
      const { data: marcada } = await admin
        .from("live_salas")
        .update({ [coluna]: new Date().toISOString() })
        .eq("id", sala.id)
        .is(coluna, null)
        .select("id");
      if (!(marcada ?? []).length) continue;
      const { data: acessos } = await admin
        .from("digital_entitlements")
        .select("order_id,catalog_order_id,client_id,clients(email)")
        .eq("user_id", sala.user_id)
        .eq("product_id", sala.product_id)
        .in("status", ["ativo", "agendado"])
        .limit(5000);
      const vistos = new Set<string>();
      const linhas: Array<Record<string, unknown>> = [];
      for (const acesso of (acessos ?? []) as unknown as Array<{
        order_id: string | null;
        catalog_order_id: string | null;
        client_id: string | null;
        clients: { email?: string | null } | null;
      }>) {
        const email = String(acesso.clients?.email || "").trim().toLowerCase();
        if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email) || vistos.has(email)) continue;
        vistos.add(email);
        linhas.push({
          user_id: sala.user_id,
          tipo: "lembrete_da_live",
          destino: email,
          dados: { sala_id: sala.id, quando, order_id: acesso.order_id, catalog_order_id: acesso.catalog_order_id, client_id: acesso.client_id },
          chave_unica: `live:${sala.id}:${quando}:${email}`,
        });
      }
      for (let i = 0; i < linhas.length; i += 500) {
        const { error } = await admin.from("digital_outbox").upsert(linhas.slice(i, i + 500), { onConflict: "chave_unica", ignoreDuplicates: true });
        if (error) console.error("[live] lembretes: a fila não aceitou", error.message);
      }
      postos += linhas.length;
    }
  }
  return postos;
}

/*
 * A live que ficou no ar esquecida (a aba de quem apresenta fechou e ninguém
 * encerrou): fecha sozinha 3 horas depois do fim previsto.
 */
export async function encerrarLivesEsquecidas(admin: Admin, lojas: string[] | null): Promise<void> {
  let consulta = admin.from("live_salas").select("id,iniciada_em,duracao_min").eq("status", "ao_vivo").limit(100);
  if (lojas) consulta = consulta.in("user_id", lojas);
  const { data } = await consulta;
  const agora = Date.now();
  for (const sala of (data ?? []) as Array<{ id: string; iniciada_em: string | null; duracao_min: number }>) {
    const inicio = sala.iniciada_em ? new Date(sala.iniciada_em).getTime() : agora;
    if (agora < inicio + (sala.duracao_min + 180) * 60000) continue;
    await admin
      .from("live_salas")
      .update({ status: "encerrada", encerrada_em: new Date().toISOString(), atualizado_em: new Date().toISOString() })
      .eq("id", sala.id)
      .eq("status", "ao_vivo");
  }
}

function quandoPorExtenso(iso: string) {
  try {
    return new Intl.DateTimeFormat("pt-BR", { weekday: "long", day: "2-digit", month: "long", hour: "2-digit", minute: "2-digit", timeZone: "America/Sao_Paulo" }).format(new Date(iso));
  } catch {
    return iso;
  }
}

function horaDeBrasilia(iso: string) {
  try {
    return new Intl.DateTimeFormat("pt-BR", { hour: "2-digit", minute: "2-digit", timeZone: "America/Sao_Paulo" }).format(new Date(iso));
  } catch {
    return "";
  }
}

/* "hoje" ou "amanhã" no relógio de Brasília (o lembrete "do dia" sai entre 2 h e 24 h antes). */
export function diaRelativo(iso: string, agora = Date.now()): "hoje" | "amanhã" {
  const dia = (t: number) => new Date(t - 3 * 3600000).toISOString().slice(0, 10);
  return dia(new Date(iso).getTime()) === dia(agora) ? "hoje" : "amanhã";
}

/* O e-mail do lembrete. O botão leva ao link da compra (que já entra), ou à área de membros. */
export async function montarLembreteDaLive(
  admin: Admin,
  params: { lojaId: string; salaId: string; quando: QuandoDoLembrete; orderId: string | null; catalogOrderId: string | null; clienteId: string | null; destino: string },
): Promise<MontagemDaEntrega> {
  const para = String(params.destino || "").trim().toLowerCase();
  if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(para)) return { ok: false, motivo: "e-mail inválido", definitivo: true };
  const [salaR, loja, perfil, cliente] = await Promise.all([
    admin.from("live_salas").select("id,titulo,comeca_em,status,espera_min").eq("id", params.salaId).eq("user_id", params.lojaId).maybeSingle(),
    lerLojaDosDigitais(admin, params.lojaId),
    admin.from("profiles").select("company_email,email").eq("id", params.lojaId).maybeSingle(),
    params.clienteId ? admin.from("clients").select("name").eq("id", params.clienteId).maybeSingle() : Promise.resolve({ data: null }),
  ]);
  const sala = salaR.data as { id: string; titulo: string; comeca_em: string; status: string; espera_min: number } | null;
  if (!sala) return { ok: false, motivo: "a live não existe mais", definitivo: true };
  if (sala.status === "cancelada" || sala.status === "encerrada") return { ok: false, motivo: "a live não acontece mais", definitivo: true };
  /* O de 15 minutos que atrasou demais não sai (a live já vai longe). */
  if (params.quando === "15" && Date.now() > new Date(sala.comeca_em).getTime() + 20 * 60000) return { ok: false, motivo: "passou da hora", definitivo: true };
  const base = baseDaLojaSemPedido(loja, process.env);
  if (!base) return { ok: false, motivo: "a loja não tem endereço público", definitivo: false };
  const link =
    (params.orderId
      ? await criarLinkDaEntrega(admin, { lojaId: params.lojaId, orderId: params.orderId, clienteId: params.clienteId, catalogOrderId: params.catalogOrderId, base })
      : null) ?? `${base}/membros`;
  const primeiroNome = String((cliente.data as { name?: string | null } | null)?.name || "").trim().split(/\s+/)[0] || "";
  const hora = horaDeBrasilia(sala.comeca_em);
  const quinze = params.quando === "15";
  const qualDia = diaRelativo(sala.comeca_em);
  const conteudo = montarEmailDaLoja({
    loja: { nome: loja.nome, logo: loja.logo, cor: loja.cor },
    resumo: quinze ? `Começa às ${hora}. A sala já está aberta.` : `A live é ${quandoPorExtenso(sala.comeca_em)}.`,
    titulo: quinze ? (primeiroNome ? `${primeiroNome}, a live já vai começar!` : "A live já vai começar!") : primeiroNome ? `${primeiroNome}, a live é ${qualDia}` : `A live é ${qualDia}`,
    paragrafos: [
      quinze
        ? `${sala.titulo} começa às ${hora} (horário de Brasília). Entre agora pela sala de espera e garanta o seu lugar no bate-papo.`
        : `Passando para lembrar: ${sala.titulo} é ${quandoPorExtenso(sala.comeca_em)} (horário de Brasília).`,
      quinze ? "Use fone de ouvido se puder. Para falar, é só levantar a mão na sala." : sala.espera_min > 0 ? `A sala de espera abre ${sala.espera_min} minutos antes. Você recebe outro aviso 15 minutos antes.` : "Você recebe outro aviso 15 minutos antes.",
    ],
    botao: { texto: quinze ? "Entrar na live" : "Ver a live", link },
    observacao: "Este link é só seu: não encaminhe este e-mail.",
  });
  const perfilDaLoja = (perfil.data ?? {}) as { company_email?: string | null; email?: string | null };
  return {
    ok: true,
    email: {
      para,
      assunto: (quinze ? `Começa às ${hora}: ${sala.titulo}` : `${qualDia === "hoje" ? "Hoje" : "Amanhã"} às ${hora}: ${sala.titulo}`).slice(0, 160),
      html: conteudo.html,
      texto: conteudo.texto,
      nomeDaLoja: loja.nome,
      responderPara: String(perfilDaLoja.company_email || perfilDaLoja.email || "").trim() || null,
      link,
      lembrarEm24h: false,
    },
  };
}
