/*
  Os blocos novos da página inicial, do lado do painel: nome e resumo de
  cada tipo, a configuração com que nasce, o que impede publicar e as
  contas de data e hora (o lojista escreve na hora de Brasília).

  Regras puras, sem "@/": o teste roda sozinho (widgets-da-home.test.ts). A
  loja tem a leitura completa em apps/public/src/lib/widgets-da-home.ts
  (os dois apps não dividem pacote); mudou lá, confira aqui.
*/

import { lerLinkDeVideo } from "./digitais/curso.ts";

export const MODOS_DOS_WIDGETS = [
  "flash_offer",
  "coupon_highlight",
  "order_cutoff",
  "next_live",
  "auto_list",
  "combo_highlight",
  "recently_viewed",
  "video_section",
  "text_image",
  "faq",
  "store_location",
  "marquee",
  "shoppable_image",
  "before_after",
] as const;

export type ModoDoWidget = (typeof MODOS_DOS_WIDGETS)[number];

export function ehWidget(valor: unknown): valor is ModoDoWidget {
  return typeof valor === "string" && (MODOS_DOS_WIDGETS as readonly string[]).includes(valor);
}

export const NOME_DO_WIDGET: Record<ModoDoWidget, string> = {
  flash_offer: "Oferta relâmpago",
  coupon_highlight: "Cupom em destaque",
  order_cutoff: "Peça até tal hora",
  next_live: "Próxima live",
  auto_list: "Lista automática",
  combo_highlight: "Kits e combos",
  recently_viewed: "Vistos recentemente",
  video_section: "Vídeo",
  text_image: "Texto com imagem",
  faq: "Perguntas frequentes",
  store_location: "Onde estamos",
  marquee: "Faixa que desliza",
  shoppable_image: "Imagem com pontos",
  before_after: "Antes e depois",
};

export const RESUMO_DO_WIDGET: Record<ModoDoWidget, string> = {
  flash_offer: "Produtos com relógio até o fim da oferta.",
  coupon_highlight: "Um cupom ativo, com o botão de copiar.",
  order_cutoff: "O tempo até o corte de produção do dia.",
  next_live: "A próxima live de venda, com contagem.",
  auto_list: "Lançamentos ou mais vendidos de verdade.",
  combo_highlight: "Os “compre junto” da loja, lado a lado.",
  recently_viewed: "O que o visitante já abriu (no navegador dele).",
  video_section: "YouTube ou Vimeo, com texto ao lado.",
  text_image: "Um texto com foto e botão.",
  faq: "Perguntas e respostas que abrem e fecham.",
  store_location: "Endereço, horários, mapa e rota.",
  marquee: "Frases curtas passando numa faixa.",
  shoppable_image: "Uma foto com pontos que mostram produtos.",
  before_after: "Duas fotos com a barra de arrastar.",
};

export const LIMITE_DA_OFERTA = 12;
export const LIMITE_DE_PERGUNTAS = 20;
export const LIMITE_DA_FAIXA = 12;
export const LIMITE_DE_PONTOS = 12;

export type ProporcaoDoWidget = "quadrado" | "retrato" | "paisagem" | "faixa";
/* faixa = 16:9 (o formato largo dos pontos e do antes e depois). */
export const PROPORCOES_DO_WIDGET: Record<ProporcaoDoWidget, { nome: string; medida: string; proporcao: number; largura: number; altura: number }> = {
  quadrado: { nome: "Quadrado", medida: "1:1", proporcao: 1, largura: 1200, altura: 1200 },
  retrato: { nome: "Retrato", medida: "4:5", proporcao: 4 / 5, largura: 960, altura: 1200 },
  paisagem: { nome: "Paisagem", medida: "8:5", proporcao: 8 / 5, largura: 1440, altura: 900 },
  faixa: { nome: "Largo", medida: "16:9", proporcao: 16 / 9, largura: 1600, altura: 900 },
};

/* ------------------------------------------------ hora de Brasília */

const FORMATO = new Intl.DateTimeFormat("en-US", {
  timeZone: "America/Sao_Paulo",
  year: "numeric",
  month: "2-digit",
  day: "2-digit",
  hour: "2-digit",
  minute: "2-digit",
  second: "2-digit",
  hourCycle: "h23",
});

function partes(instante: number) {
  const p = Object.fromEntries(FORMATO.formatToParts(new Date(instante)).map((x) => [x.type, x.value]));
  return { ano: Number(p.year), mes: Number(p.month), dia: Number(p.day), hora: Number(p.hour) % 24, minuto: Number(p.minute), segundo: Number(p.second) };
}

function diferenca(instante: number) {
  const p = partes(instante);
  return Date.UTC(p.ano, p.mes - 1, p.dia, p.hora, p.minuto, p.segundo) - Math.floor(instante / 1000) * 1000;
}

/** "2026-10-20T18:00" (hora de Brasília) → o instante. Inválido: null. */
export function instanteDeBrasilia(valor: unknown): number | null {
  const achado = /^(\d{4})-(\d{2})-(\d{2})[T ](\d{2}):(\d{2})$/.exec(String(valor ?? "").trim());
  if (!achado) return null;
  const [ano, mes, dia, hora, minuto] = achado.slice(1).map(Number);
  if (mes < 1 || mes > 12 || dia < 1 || dia > 31 || hora > 23 || minuto > 59) return null;
  const comoUtc = Date.UTC(ano, mes - 1, dia, hora, minuto);
  let instante = comoUtc - diferenca(comoUtc);
  instante = comoUtc - diferenca(instante);
  return instante;
}

/** O instante no formato do campo de data e hora (hora de Brasília). */
export function textoDeBrasilia(instante: number) {
  const p = partes(instante);
  const dois = (n: number) => String(n).padStart(2, "0");
  return `${p.ano}-${dois(p.mes)}-${dois(p.dia)}T${dois(p.hora)}:${dois(p.minuto)}`;
}

/** Só YouTube e Vimeo na loja. */
export function linkDeVideoValido(url: unknown) {
  const link = lerLinkDeVideo(String(url ?? ""));
  return Boolean(link && (link.provedor === "youtube" || link.provedor === "vimeo"));
}

/* ------------------------------------------------ como cada um nasce */

type Base = {
  title: string;
  layout_width: "full" | "contained";
  title_align: "left" | "center" | "right";
  config: Record<string, unknown>;
};

/** O começo de cada bloco: título, alinhamento e o que a tela sugere. */
export function widgetNovo(modo: ModoDoWidget, agora = Date.now()): Base {
  const amanha = textoDeBrasilia(agora + 24 * 3600 * 1000).slice(0, 11) + "23:59";
  switch (modo) {
    case "flash_offer":
      return { title: "Oferta relâmpago", layout_width: "contained", title_align: "left", config: { mode: modo, produtos: [], termina_em: amanha, selo: "Oferta", subtitulo: "" } };
    case "coupon_highlight":
      return { title: "Cupom de boas-vindas", layout_width: "contained", title_align: "left", config: { mode: modo, cupom_id: "", chamada: "Use na sua primeira compra", mostrar_validade: true } };
    case "order_cutoff":
      return { title: "Peça até tal hora", layout_width: "contained", title_align: "left", config: { mode: modo, margem: "pequeno" } };
    case "next_live":
      return { title: "Live de vendas", layout_width: "contained", title_align: "left", config: { mode: modo, mostrar_sem_live: false, mensagem_sem_live: "" } };
    case "auto_list":
      return { title: "Lançamentos", layout_width: "full", title_align: "left", config: { mode: modo, lista: "lancamentos", dias: 30, quantidade: 8 } };
    case "combo_highlight":
      return { title: "Kits que saem juntos", layout_width: "contained", title_align: "left", config: { mode: modo, quantidade: 6, combos: [] } };
    case "recently_viewed":
      return { title: "Vistos recentemente", layout_width: "contained", title_align: "left", config: { mode: modo, quantidade: 8 } };
    case "video_section":
      return { title: "Veja como fazemos", layout_width: "contained", title_align: "center", config: { mode: modo, url: "", texto: "", lado: "inteiro", capa: "" } };
    case "text_image":
      return {
        title: "Sobre a nossa loja",
        layout_width: "contained",
        title_align: "left",
        config: { mode: modo, chamada: "", texto: "", imagem: "", lado: "esquerda", proporcao: "quadrado", botao_texto: "", botao_link: { tipo: "nenhum" } },
      };
    case "faq":
      return { title: "Perguntas frequentes", layout_width: "contained", title_align: "left", config: { mode: modo, itens: [{ pergunta: "", resposta: "" }], abrir_primeira: true } };
    case "store_location":
      return {
        title: "Onde estamos",
        layout_width: "contained",
        title_align: "left",
        config: { mode: modo, usar_endereco_da_loja: true, endereco: "", horarios: "Segunda a sexta, das 9h às 18h\nSábado, das 9h às 13h", mostrar_mapa: true, mostrar_retiradas: false },
      };
    case "marquee":
      return {
        title: "Faixa que desliza",
        layout_width: "full",
        title_align: "left",
        config: { mode: modo, itens: ["Frete para todo o Brasil", "Parcele em até 12x", "Atendimento pelo WhatsApp"], velocidade: "normal", cor_de_fundo: "", cor_do_texto: "#ffffff", tamanho: "m" },
      };
    case "shoppable_image":
      return { title: "Compre o look", layout_width: "contained", title_align: "left", config: { mode: modo, imagem: "", proporcao: "paisagem", pontos: [] } };
    case "before_after":
      return {
        title: "Antes e depois",
        layout_width: "contained",
        title_align: "center",
        config: { mode: modo, antes: "", depois: "", rotulo_antes: "Antes", rotulo_depois: "Depois", proporcao: "paisagem", inicio: 50 },
      };
  }
}

/* --------------------------------------------- o que impede publicar */

/** O que falta para o bloco ir para a loja (null = pode publicar). */
export function problemaDoWidget(modo: ModoDoWidget, c: Record<string, unknown>, agora = Date.now()): string | null {
  switch (modo) {
    case "flash_offer": {
      const fim = instanteDeBrasilia(c.termina_em);
      if (fim === null) return "escolha a data e a hora em que a oferta termina.";
      if (!Array.isArray(c.produtos) || !c.produtos.length) return "escolha os produtos da oferta.";
      /* Oferta vencida não trava a publicação: ela só some da loja. */
      void agora;
      return null;
    }
    case "coupon_highlight":
      return c.cupom_id ? null : "escolha o cupom.";
    case "video_section":
      return linkDeVideoValido(c.url) ? null : "cole o link de um vídeo do YouTube ou do Vimeo.";
    case "faq": {
      const itens = Array.isArray(c.itens) ? (c.itens as Array<Record<string, unknown>>) : [];
      const meias = itens.filter((i) => Boolean(String(i?.pergunta ?? "").trim()) !== Boolean(String(i?.resposta ?? "").trim()));
      if (meias.length) return "toda pergunta precisa de resposta (e toda resposta, de pergunta).";
      return itens.some((i) => String(i?.pergunta ?? "").trim()) ? null : "escreva ao menos uma pergunta com resposta.";
    }
    case "store_location":
      return c.usar_endereco_da_loja === false && !String(c.endereco ?? "").trim() ? "escreva o endereço (ou use o da empresa)." : null;
    case "marquee":
      return Array.isArray(c.itens) && c.itens.some((i) => String(i ?? "").trim()) ? null : "escreva ao menos uma frase.";
    case "before_after":
      return c.antes && c.depois ? null : "escolha as duas imagens.";
    case "shoppable_image":
      return c.imagem ? null : "escolha a imagem.";
    default:
      return null;
  }
}
