/*
  O expediente do atendimento.

  Online e offline no braço tem um problema conhecido: ninguém lembra de
  desligar. A loja fica dizendo "estamos online" às onze da noite, o visitante
  escreve achando que alguém vai responder na hora, e a primeira impressão da
  loja é a de quem promete e não cumpre.

  Aqui o relógio faz esse trabalho. O horário é o de Brasília — o produto é
  brasileiro e a loja pensa no horário dela, não no do servidor, que roda em
  UTC.
*/

const FUSO = "America/Sao_Paulo";
const DIAS = ["dom", "seg", "ter", "qua", "qui", "sex", "sab"] as const;

export type FaixaDoDia = { dia: string; aberto: boolean; de: string; ate: string };

export function agoraNaLoja(quando = new Date()) {
  const partes = new Intl.DateTimeFormat("pt-BR", {
    timeZone: FUSO,
    weekday: "short",
    hour: "2-digit",
    minute: "2-digit",
    hour12: false,
  }).formatToParts(quando);

  const pegar = (tipo: string) => partes.find((parte) => parte.type === tipo)?.value || "";
  const hora = pegar("hour").padStart(2, "0");
  const minuto = pegar("minute").padStart(2, "0");

  /* O nome do dia vem como "seg.", "sáb." — o índice é mais confiável. */
  const indice = new Date(quando.toLocaleString("en-US", { timeZone: FUSO })).getDay();

  return { dia: DIAS[indice], hhmm: `${hora}:${minuto}` };
}

/*
  Está aberto agora?

  Faixa que vira a meia-noite (das 18h às 2h) conta como aberta dos dois lados
  do relógio: quem atende de madrugada não pode ser fechado pela conta ingênua
  de "início menor que fim".
*/
export function dentroDoExpediente(horario: unknown, quando = new Date()) {
  if (!Array.isArray(horario) || !horario.length) return true;

  const { dia, hhmm } = agoraNaLoja(quando);
  const faixa = (horario as FaixaDoDia[]).find((item) => item?.dia === dia);
  if (!faixa || !faixa.aberto) return false;

  const de = String(faixa.de || "00:00");
  const ate = String(faixa.ate || "23:59");

  if (de <= ate) return hhmm >= de && hhmm <= ate;
  return hhmm >= de || hhmm <= ate;
}

/* Quando a loja volta a atender: é o que dá para prometer sem mentir. */
export function proximaAbertura(horario: unknown, quando = new Date()) {
  if (!Array.isArray(horario) || !horario.length) return null;
  const faixas = horario as FaixaDoDia[];
  const { dia } = agoraNaLoja(quando);
  const comeco = DIAS.indexOf(dia as (typeof DIAS)[number]);

  for (let passo = 0; passo < 8; passo += 1) {
    const indice = (comeco + passo) % 7;
    const faixa = faixas.find((item) => item?.dia === DIAS[indice]);
    if (!faixa?.aberto) continue;
    if (passo === 0 && dentroDoExpediente(horario, quando)) return null;
    if (passo === 0 && agoraNaLoja(quando).hhmm > String(faixa.ate || "")) continue;
    const nome = passo === 0 ? "hoje" : passo === 1 ? "amanhã" : NOMES[indice];
    return `${nome} às ${faixa.de}`;
  }
  return null;
}

const NOMES: Record<number, string> = {
  0: "domingo",
  1: "segunda",
  2: "terça",
  3: "quarta",
  4: "quinta",
  5: "sexta",
  6: "sábado",
};
