import assert from "node:assert/strict";
import { test } from "node:test";

import { conferirPartes, partesParaFechar, resumoDasPartes } from "./gravacao-partes.ts";

const MB = 1024 * 1024;
const parte = (numero: number, tamanho: number, etag = `"e${numero}"`) => ({ numero, etag, tamanho });

test("partes iguais com a última menor fecham", () => {
  assert.deepEqual(conferirPartes([parte(1, 8 * MB), parte(2, 8 * MB), parte(3, 123)]), { ok: true });
  assert.deepEqual(conferirPartes([parte(3, 8 * MB), parte(1, 8 * MB), parte(2, 8 * MB)]), { ok: true });
  assert.deepEqual(conferirPartes([parte(1, 4000)]), { ok: true });
});

test("o caso de 17/10: uma parte pequena no meio (dois gravadores no mesmo envio)", () => {
  const partes = Array.from({ length: 203 }, (_, i) => parte(i + 1, 8 * MB));
  partes[99] = parte(100, 3 * MB);
  const r = conferirPartes(partes);
  assert.equal(r.ok, false);
  assert.match(!r.ok ? r.motivo : "", /parte 100/);
});

test("buraco, repetida, sem etiqueta, primeira pequena e última maior não fecham", () => {
  assert.match(String((conferirPartes([parte(1, 8 * MB), parte(3, 1)]) as { motivo: string }).motivo), /falta a parte 2/);
  assert.match(String((conferirPartes([parte(1, 8 * MB), parte(1, 8 * MB)]) as { motivo: string }).motivo), /repetida/);
  assert.match(String((conferirPartes([parte(1, 8 * MB, ""), parte(2, 1)]) as { motivo: string }).motivo), /etiqueta/);
  assert.match(String((conferirPartes([parte(1, 4 * MB), parte(2, 1)]) as { motivo: string }).motivo), /5 MiB/);
  assert.match(String((conferirPartes([parte(1, 6 * MB), parte(2, 7 * MB)]) as { motivo: string }).motivo), /maior/);
  assert.equal(conferirPartes([]).ok, false);
});

test("sem tamanho conhecido, confere só a ordem", () => {
  assert.deepEqual(conferirPartes([{ numero: 1, etag: "a" }, { numero: 2, etag: "b" }], false), { ok: true });
  assert.equal(conferirPartes([{ numero: 1, etag: "a" }, { numero: 2, etag: "b" }]).ok, false);
});

test("o depósito é a verdade; o banco só quando ele não listou", () => {
  const banco = [parte(1, 8 * MB, '"velha"')];
  const deposito = [parte(2, 5), parte(1, 8 * MB, '"nova"')];
  assert.deepEqual(partesParaFechar(banco, deposito), { partes: [parte(1, 8 * MB, '"nova"'), parte(2, 5)], fonte: "deposito" });
  assert.equal(partesParaFechar(banco, []).fonte, "banco");
  assert.equal(partesParaFechar(banco, null).fonte, "banco");
});

test("resumo para o registro", () => {
  const r = resumoDasPartes([parte(1, 8), parte(2, 8), parte(4, 3), parte(4, 3)]);
  assert.deepEqual(r, { partes: 4, bytes: 22, tamanhos: { "8": 2, "3": 2 }, faltam: [3], repetidas: [4] });
});
