import { test } from "node:test";
import assert from "node:assert/strict";
import { EXPEDIENTE_PADRAO } from "./expediente.ts";
import { resumirProducao, rotuloDaEtapa, type EventoDeProducao } from "./eventos-de-producao.ts";

const SP = (dia: string, hora: string) => `${dia}T${hora}:00-03:00`;

function evento(parte: Partial<EventoDeProducao> & Pick<EventoDeProducao, "kind" | "started_at">): EventoDeProducao {
  return {
    id: parte.id ?? `${parte.kind}-${parte.started_at}`,
    status: null,
    stage_id: null,
    stage_label: null,
    order_item_id: null,
    item_title: null,
    ended_at: null,
    started_by: null,
    ended_by: null,
    source: "evento",
    ...parte,
  };
}

/* Um pedido que entrou segunda de manhã, foi para produção à tarde, teve o
   cronômetro esquecido ligado de noite, e foi finalizado terça. */
const EVENTOS: EventoDeProducao[] = [
  evento({ kind: "etapa", status: "pending_production", started_at: SP("2026-08-31", "09:00"), ended_at: SP("2026-08-31", "14:00") }),
  evento({ kind: "etapa", status: "in_production", stage_label: "Impressão", started_at: SP("2026-08-31", "14:00"), ended_at: SP("2026-09-01", "10:00") }),
  evento({ kind: "etapa", status: "finished", started_at: SP("2026-09-01", "10:00") }),
  evento({ kind: "cronometro", status: "in_production", started_at: SP("2026-08-31", "14:00"), ended_at: SP("2026-09-01", "10:00"), started_by: "u1" }),
  evento({ id: "i1", kind: "item", order_item_id: "item-a", item_title: "Banner", started_at: SP("2026-08-31", "14:10"), ended_at: SP("2026-08-31", "15:40"), started_by: "u2" }),
  evento({ id: "i2", kind: "item", order_item_id: "item-a", item_title: "Banner", started_at: SP("2026-09-01", "08:00"), ended_at: SP("2026-09-01", "08:30"), started_by: "u2" }),
  evento({ id: "i3", kind: "item", order_item_id: "item-b", item_title: "Chaveiro", started_at: SP("2026-09-01", "09:00"), started_by: "u1" }),
];

const AGORA = Date.parse(SP("2026-09-01", "11:00"));
const NOMES: Record<string, string> = { u1: "Ana", u2: "Bruno" };

test("etapas: tempo corrido, tempo útil e a terminal aberta", () => {
  const r = resumirProducao(EVENTOS, EXPEDIENTE_PADRAO, AGORA, (id) => NOMES[id] ?? null);
  assert.equal(r.etapas.length, 3);

  const [aguardando, producao, finalizado] = r.etapas;
  assert.equal(aguardando.rotulo, "Aguardando produção");
  assert.equal(aguardando.minutos, 300);
  assert.equal(aguardando.minutosUteis, 300);

  assert.equal(producao.rotulo, "Impressão");
  /* 20 h de relógio: 4 h de segunda + 2 h de terça dentro do expediente. */
  assert.equal(producao.minutos, 1200);
  assert.equal(producao.minutosUteis, 360);
  assert.equal(producao.aberta, false);

  assert.equal(finalizado.aberta, true);
  assert.equal(finalizado.terminal, true);
  assert.equal(finalizado.minutos, 60);
});

test("cronômetro: corrido × útil, com quem ligou", () => {
  const r = resumirProducao(EVENTOS, EXPEDIENTE_PADRAO, AGORA, (id) => NOMES[id] ?? null);
  assert.equal(r.sessoes.length, 1);
  assert.equal(r.sessoes[0].porNome, "Ana");
  assert.equal(r.tempoCorridoMin, 1200);
  assert.equal(r.tempoUtilMin, 360);
});

test("apontamento por item: feitos somam, aberto conta até agora", () => {
  const r = resumirProducao(EVENTOS, EXPEDIENTE_PADRAO, AGORA, (id) => NOMES[id] ?? null);
  const banner = r.itens.find((i) => i.orderItemId === "item-a");
  const chaveiro = r.itens.find((i) => i.orderItemId === "item-b");
  assert.ok(banner && chaveiro);

  assert.equal(banner.titulo, "Banner");
  assert.equal(banner.feitos.length, 2);
  assert.equal(banner.minutosReais, 120);
  assert.equal(banner.aberto, null);
  assert.equal(banner.feitos[0].porNome, "Bruno");

  assert.equal(chaveiro.aberto?.minutos, 120);
  assert.equal(chaveiro.aberto?.porNome, "Ana");
  assert.equal(chaveiro.feitos.length, 0);
  assert.equal(chaveiro.minutosReais, 0);
});

test("sessão aberta do cronômetro conta até agora, dentro do expediente", () => {
  const r = resumirProducao(
    [evento({ kind: "cronometro", started_at: SP("2026-08-31", "17:00") })],
    EXPEDIENTE_PADRAO,
    AGORA
  );
  assert.equal(r.sessoes[0].aberta, true);
  assert.equal(r.tempoCorridoMin, 18 * 60);
  /* 1 h de segunda + 3 h de terça. */
  assert.equal(r.tempoUtilMin, 240);
});

test("sem eventos, tudo zero e vazio", () => {
  const r = resumirProducao([], EXPEDIENTE_PADRAO, AGORA);
  assert.deepEqual(r, { etapas: [], sessoes: [], tempoCorridoMin: 0, tempoUtilMin: 0, itens: [] });
});

test("rótulo da etapa: coluna personalizada vence o status", () => {
  assert.equal(rotuloDaEtapa({ status: "in_production", stage_label: "Acabamento" }), "Acabamento");
  assert.equal(rotuloDaEtapa({ status: "in_production", stage_label: "  " }), "Em produção");
  assert.equal(rotuloDaEtapa({ status: "xyz", stage_label: null }), "xyz");
});

test("eventos do histórico vêm marcados como aproximados", () => {
  const r = resumirProducao(
    [evento({ kind: "etapa", status: "pending_production", started_at: SP("2026-08-31", "09:00"), source: "historico" })],
    EXPEDIENTE_PADRAO,
    AGORA
  );
  assert.equal(r.etapas[0].aproximada, true);
});
