/*
  Como uma seção aparece na loja, do lado do painel: agendar (janela na hora
  de Brasília), mostrar só no celular ou só no computador, o fundo da seção
  e o espaço acima e abaixo. Vale para qualquer tipo de seção e mora na
  própria configuração (config.agendamento, config.dispositivo,
  config.fundo_da_secao). Seção sem nada disso sai como sempre saiu.

  Regras puras, sem "@/": o teste roda sozinho (exibicao-da-secao.test.ts). A
  loja tem a leitura completa (e o desenho) em
  apps/public/src/lib/exibicao-da-secao.ts; mudou lá, muda aqui.
*/

import { instanteDeBrasilia, textoDeBrasilia } from "./widgets-da-home.ts";

export type Dispositivo = "todos" | "celular" | "computador";
export type TipoDeFundo = "nenhum" | "cor" | "gradiente" | "imagem";
export type Espaco = "" | "p" | "m" | "g";

export type FundoDaSecao = {
  tipo: TipoDeFundo;
  cor: string;
  cor_2: string;
  angulo: number;
  imagem: string;
  escurecer: number;
  largura: "inteira" | "contida";
  acima: Espaco;
  abaixo: Espaco;
  /* Textos brancos sobre o fundo: true, false, ou null (automático: claro
     sobre imagem escurecida ou cor escura). */
  texto_claro: boolean | null;
};

export const FUNDO_PADRAO: FundoDaSecao = {
  tipo: "nenhum",
  cor: "#f4f0ff",
  cor_2: "#ffffff",
  angulo: 135,
  imagem: "",
  escurecer: 35,
  largura: "inteira",
  acima: "",
  abaixo: "",
  texto_claro: null,
};

export const NOME_DO_DISPOSITIVO: Record<Dispositivo, string> = {
  todos: "Celular e computador",
  celular: "Só no celular",
  computador: "Só no computador",
};

export const NOME_DO_ESPACO: Record<Espaco, string> = { "": "Normal", p: "P", m: "M", g: "G" };

const DATA_E_HORA = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}$/;

function objeto(valor: unknown): Record<string, unknown> | null {
  return valor && typeof valor === "object" && !Array.isArray(valor) ? (valor as Record<string, unknown>) : null;
}

function cor(valor: unknown, padrao: string) {
  const texto = String(valor ?? "").trim();
  return /^#([0-9a-f]{3}|[0-9a-f]{6})$/i.test(texto) ? texto : padrao;
}

function espaco(valor: unknown): Espaco {
  return valor === "p" || valor === "m" || valor === "g" ? valor : "";
}

export type Agendamento = { inicio: string; fim: string };

/** O agendamento como o campo de data e hora mostra ("" = sem). */
export function lerAgendamento(config: Record<string, unknown>): Agendamento {
  const bruto = objeto(config.agendamento);
  const inicio = String(bruto?.inicio ?? "");
  const fim = String(bruto?.fim ?? "");
  return {
    inicio: DATA_E_HORA.test(inicio) && instanteDeBrasilia(inicio) !== null ? inicio : "",
    fim: DATA_E_HORA.test(fim) && instanteDeBrasilia(fim) !== null ? fim : "",
  };
}

export function lerDispositivo(config: Record<string, unknown>): Dispositivo {
  return config.dispositivo === "celular" || config.dispositivo === "computador" ? config.dispositivo : "todos";
}

export function lerFundo(config: Record<string, unknown>): FundoDaSecao {
  const bruto = objeto(config.fundo_da_secao);
  if (!bruto) return { ...FUNDO_PADRAO };
  const tipo = (["cor", "gradiente", "imagem"] as const).includes(bruto.tipo as never) ? (bruto.tipo as TipoDeFundo) : "nenhum";
  const angulo = Math.round(Number(bruto.angulo));
  const escurecer = Math.round(Number(bruto.escurecer));
  return {
    tipo,
    cor: cor(bruto.cor, FUNDO_PADRAO.cor),
    cor_2: cor(bruto.cor_2, FUNDO_PADRAO.cor_2),
    angulo: Number.isFinite(angulo) ? ((angulo % 360) + 360) % 360 : FUNDO_PADRAO.angulo,
    imagem: typeof bruto.imagem === "string" ? bruto.imagem.slice(0, 2000) : "",
    escurecer: Number.isFinite(escurecer) ? Math.min(80, Math.max(0, escurecer)) : FUNDO_PADRAO.escurecer,
    largura: bruto.largura === "contida" ? "contida" : "inteira",
    acima: espaco(bruto.acima),
    abaixo: espaco(bruto.abaixo),
    texto_claro: typeof bruto.texto_claro === "boolean" ? bruto.texto_claro : null,
  };
}

/**
 * A configuração com o agendamento novo. Sem início nem fim, a chave sai
 * (a seção volta a ser como era, sem nada a mais gravado).
 */
export function comAgendamento(config: Record<string, unknown>, agenda: Agendamento): Record<string, unknown> {
  const novo = { ...config };
  const inicio = DATA_E_HORA.test(agenda.inicio) ? agenda.inicio : "";
  const fim = DATA_E_HORA.test(agenda.fim) ? agenda.fim : "";
  if (!inicio && !fim) delete novo.agendamento;
  else novo.agendamento = { ...(inicio ? { inicio } : {}), ...(fim ? { fim } : {}) };
  return novo;
}

export function comDispositivo(config: Record<string, unknown>, dispositivo: Dispositivo): Record<string, unknown> {
  const novo = { ...config };
  if (dispositivo === "todos") delete novo.dispositivo;
  else novo.dispositivo = dispositivo;
  return novo;
}

/** A configuração com o fundo novo. Sem fundo e sem espaço, a chave sai. */
export function comFundo(config: Record<string, unknown>, fundo: FundoDaSecao): Record<string, unknown> {
  const novo = { ...config };
  if (fundo.tipo === "nenhum" && !fundo.acima && !fundo.abaixo) {
    delete novo.fundo_da_secao;
    return novo;
  }
  const gravado: Record<string, unknown> = { tipo: fundo.tipo, largura: fundo.largura };
  if (fundo.acima) gravado.acima = fundo.acima;
  if (fundo.abaixo) gravado.abaixo = fundo.abaixo;
  if (fundo.tipo === "cor" || fundo.tipo === "gradiente") gravado.cor = fundo.cor;
  if (fundo.tipo === "gradiente") {
    gravado.cor_2 = fundo.cor_2;
    gravado.angulo = fundo.angulo;
  }
  if (fundo.tipo === "imagem") {
    gravado.imagem = fundo.imagem;
    gravado.escurecer = fundo.escurecer;
  }
  if (fundo.tipo !== "nenhum" && typeof fundo.texto_claro === "boolean") gravado.texto_claro = fundo.texto_claro;
  novo.fundo_da_secao = gravado;
  return novo;
}

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

/** O que está errado no agendamento (null = certo). */
export function problemaDoAgendamento(agenda: Agendamento): string | null {
  if (!agenda.inicio || !agenda.fim) return null;
  const inicio = instanteDeBrasilia(agenda.inicio);
  const fim = instanteDeBrasilia(agenda.fim);
  if (inicio !== null && fim !== null && fim <= inicio) return "o fim do agendamento precisa ser depois do início.";
  return null;
}

export function problemaDaExibicao(config: Record<string, unknown>): string | null {
  const agenda = problemaDoAgendamento(lerAgendamento(config));
  if (agenda) return agenda;
  const fundo = lerFundo(config);
  if (fundo.tipo === "imagem" && !/^https:\/\//i.test(fundo.imagem)) return "escolha a imagem do fundo (ou outro tipo de fundo).";
  return null;
}

/* --------------------------------------------------------------- textos */

function quando(texto: string) {
  const [data, hora] = texto.split("T");
  const [, mes, dia] = data.split("-");
  return `${dia}/${mes} às ${hora}`;
}

/** "Agendada: aparece de 20/10 às 08:00 até 25/10 às 23:59" ("" sem agendamento). */
export function textoDoAgendamento(agenda: Agendamento): string {
  if (agenda.inicio && agenda.fim) return `Agendada: aparece de ${quando(agenda.inicio)} até ${quando(agenda.fim)}`;
  if (agenda.inicio) return `Agendada: aparece a partir de ${quando(agenda.inicio)}`;
  if (agenda.fim) return `Agendada: aparece até ${quando(agenda.fim)}`;
  return "";
}

export type MomentoDaAgenda = "sem" | "antes" | "no_ar" | "depois";

export function momentoDaAgenda(agenda: Agendamento, agora = Date.now()): MomentoDaAgenda {
  const inicio = agenda.inicio ? instanteDeBrasilia(agenda.inicio) : null;
  const fim = agenda.fim ? instanteDeBrasilia(agenda.fim) : null;
  if (inicio === null && fim === null) return "sem";
  if (inicio !== null && agora < inicio) return "antes";
  if (fim !== null && agora >= fim) return "depois";
  return "no_ar";
}

/** Um selo curto para a lista de seções ("Agendada", "Só no celular"...). */
export function selosDaExibicao(config: Record<string, unknown>, agora = Date.now()): string[] {
  const selos: string[] = [];
  const momento = momentoDaAgenda(lerAgendamento(config), agora);
  if (momento === "antes") selos.push("Agendada");
  else if (momento === "depois") selos.push("Agenda vencida");
  else if (momento === "no_ar") selos.push("No ar até o fim da agenda");
  const dispositivo = lerDispositivo(config);
  if (dispositivo !== "todos") selos.push(NOME_DO_DISPOSITIVO[dispositivo]);
  return selos;
}

/** Hoje às HH:MM, na hora de Brasília, no formato do campo. */
export function agoraEmBrasilia(agora = Date.now()) {
  return textoDeBrasilia(agora);
}
