import assert from "node:assert/strict";
import { readFileSync, readdirSync } from "node:fs";
import { test } from "node:test";

import {
  dadosDaLiveParaSalvar,
  dataEHoraBr,
  duracaoBr,
  instanteDeBrasilia,
  lerReferenciaDeArquivo,
  mesclarConfig,
  mudaPrecoNaLoja,
  tamanhoBr,
} from "./ferramentas/digitais-regras.ts";

/* ------------------------------------------------------------- datas e medidas */

test("dia e hora de Brasília viram o instante certo, e voltam", () => {
  assert.equal(instanteDeBrasilia("2026-10-20", "19:30"), "2026-10-20T22:30:00.000Z");
  assert.equal(instanteDeBrasilia("2026-10-20"), "2026-10-20T03:00:00.000Z");
  assert.equal(instanteDeBrasilia("20/10/2026", "19:30"), null);
  assert.equal(instanteDeBrasilia("2026-10-20", "25:00"), null);
  assert.equal(dataEHoraBr("2026-10-20T22:30:00.000Z"), "20/10/2026 19:30");
  assert.equal(dataEHoraBr(null), null);
});

test("duração e tamanho em português", () => {
  assert.equal(duracaoBr(0), null);
  assert.equal(duracaoBr(20), "1 min");
  assert.equal(duracaoBr(1102), "18 min");
  assert.equal(duracaoBr(3600), "1h");
  assert.equal(duracaoBr(4380), "1h 13min");
  assert.equal(tamanhoBr(2048), "2 KB");
  assert.equal(tamanhoBr(700 * 1024 * 1024), "700 MB");
  assert.equal(tamanhoBr(2 * 1024 ** 3), "2 GB");
});

/* ------------------------------------------------------------- arquivo indicado */

test("o arquivo pode vir pelo id, pelo código do envio ou pelo link inteiro", () => {
  assert.deepEqual(lerReferenciaDeArquivo("0A1B2C3D-0000-4000-8000-000000000001"), { tipo: "id", id: "0a1b2c3d-0000-4000-8000-000000000001" });
  assert.deepEqual(lerReferenciaDeArquivo("envio:Ab3dE9xK2mQp"), { tipo: "envio", codigo: "Ab3dE9xK2mQp" });
  assert.deepEqual(lerReferenciaDeArquivo("Ab3dE9xK2mQp"), { tipo: "envio", codigo: "Ab3dE9xK2mQp" });
  assert.deepEqual(lerReferenciaDeArquivo("https://admin.ktalogu.com.br/enviar/Ab3dE9xK2mQp"), { tipo: "envio", codigo: "Ab3dE9xK2mQp" });
  assert.equal(lerReferenciaDeArquivo("https://youtu.be/abc"), null);
  assert.equal(lerReferenciaDeArquivo("envio:curto"), null);
  assert.equal(lerReferenciaDeArquivo(""), null);
});

/* ------------------------------------------------------------- produto */

test("a mudança na ficha mantém o que não foi pedido", () => {
  const atual = { tipo: "arquivos", resumo: "Frase", perguntas: [{ pergunta: "P", resposta: "R" }], entrega: { modo: "na_hora", prazoDias: 3 }, limiteDeDownloads: 5 };
  const nova = mesclarConfig(atual, { resumo: "Outra", entrega: { modo: "encomenda" } });
  assert.equal(nova.resumo, "Outra");
  assert.deepEqual(nova.perguntas, atual.perguntas);
  assert.deepEqual(nova.entrega, { modo: "encomenda", prazoDias: 3 });
  assert.equal(nova.limiteDeDownloads, 5);
  assert.equal(nova.tipo, "arquivos");
  /* O original não muda. */
  assert.equal(atual.resumo, "Frase");
});

test("prazo de acesso: igual às configurações, para sempre ou dias (como a tela grava)", () => {
  assert.equal(mesclarConfig({}, { prazoDeAcessoDias: null }).acesso, null);
  assert.deepEqual(mesclarConfig({}, { prazoDeAcessoDias: 0 }).acesso, { prazoDias: null });
  assert.deepEqual(mesclarConfig({}, { prazoDeAcessoDias: 30 }).acesso, { prazoDias: 30 });
});

test("pré-venda e página de venda do conteúdo em vídeo", () => {
  assert.deepEqual(mesclarConfig({}, { preVendaEm: "2026-12-01T03:00:00.000Z" }).preVenda, { em: "2026-12-01T03:00:00.000Z" });
  assert.equal(mesclarConfig({ preVenda: { em: "x" } }, { preVendaEm: null }).preVenda, null);
  const curso = mesclarConfig(
    { tipo: "curso", curso: { aprendizados: ["a"], garantiaDias: 7, certificado: { emitir: true, cargaHoras: null }, conteudo: { aulas: 3 } } },
    { curso: { apresentacao: { link: "https://youtu.be/dQw4w9WgXcQ" }, certificado: { cargaHoras: 20 } } }
  );
  const c = curso.curso as Record<string, unknown>;
  assert.deepEqual(c.aprendizados, ["a"]);
  assert.equal(c.garantiaDias, 7);
  assert.deepEqual(c.apresentacao, { link: { url: "https://youtu.be/dQw4w9WgXcQ" } });
  assert.deepEqual(c.certificado, { emitir: true, cargaHoras: 20 });
  assert.deepEqual(c.conteudo, { aulas: 3 });
  assert.deepEqual((mesclarConfig({}, { curso: { apresentacao: { arquivoId: "id" } } }).curso as Record<string, unknown>).apresentacao, { arquivoId: "id" });
});

test("preço que muda em produto na loja pede confirmação; rascunho ou mesmo preço, não", () => {
  assert.equal(mudaPrecoNaLoja({ naLoja: true, precoAtual: 97, precoNovo: 127 }), true);
  assert.equal(mudaPrecoNaLoja({ naLoja: true, precoAtual: 97, precoNovo: 97 }), false);
  assert.equal(mudaPrecoNaLoja({ naLoja: false, precoAtual: 97, precoNovo: 10 }), false);
  assert.equal(mudaPrecoNaLoja({ naLoja: true, precoAtual: 97, precoNovo: undefined }), false);
});

/* ------------------------------------------------------------- live */

test("a live da tela vira os dados que a rota de salvar lê", () => {
  const dados = dadosDaLiveParaSalvar({ id: "x", categoria: "venda", titulo: "T", comecaEm: "2026-10-20T22:30:00.000Z", camerasAlunos: false, preco: 10, situacao: "agendada" });
  assert.equal(dados.titulo, "T");
  assert.equal(dados.camerasAlunos, false);
  assert.equal(dados.comecaEm, "2026-10-20T22:30:00.000Z");
  assert.equal("situacao" in dados, false);
  assert.equal("id" in dados, false);
});

/* ------------------------------------------------------------- as ferramentas */

const pasta = new URL("./ferramentas/", import.meta.url);
const arquivosDasFerramentas = readdirSync(pasta).filter((nome) => /^digitais-(?!regras|comum).+\.ts$/.test(nome));

test("toda ferramenta de digitais confere liberação, permissão e assinatura antes de tudo", () => {
  assert.ok(arquivosDasFerramentas.length >= 6);
  for (const nome of arquivosDasFerramentas) {
    const fonte = readFileSync(new URL(nome, pasta), "utf8");
    const blocos = fonte.split(/\nexport const \w+: Ferramenta/).slice(1);
    for (const bloco of blocos) {
      const corpo = bloco.slice(0, bloco.indexOf("\n};"));
      if (!/nome: "/.test(corpo)) continue;
      /* ver_area_digital confere a liberação antes, para responder "não liberada" sem erro. */
      assert.ok(/abrirDigital\(ctx, "digital\.[a-z]+\.(read|write)"|pedirEnvio\(ctx/.test(corpo), `${nome}: ${/nome: "([^"]+)"/.exec(corpo)?.[1]} sem abrirDigital`);
    }
  }
});

test("o que a ferramenta diz à pessoa não usa vocabulário de escola", () => {
  for (const nome of [...arquivosDasFerramentas, "digitais-comum.ts"]) {
    const fonte = readFileSync(new URL(nome, pasta), "utf8");
    /* Só os textos de uma linha (o que vai à pessoa); o código entre aspas de linhas diferentes não conta. */
    const textos = [...fonte.matchAll(/"((?:[^"\\\n]|\\.){8,})"|`((?:[^`\\\n]|\\.){8,})`/g)].map((m) => m[1] ?? m[2]);
    for (const texto of textos) {
      /* Caminhos (a pasta das imagens no depósito é a mesma da tela) não vão à pessoa. */
      if (/^[@./]|^digital\.|lib\/|from |\.ts$|^[a-z0-9/_-]+$/.test(texto)) continue;
      assert.equal(/\b(alunos?|aulas?|cursos?|professor(es)?|professora)\b/i.test(texto.replace(/\$\{[^}]*\}/g, "").replace(/\b\w+(\.\w+)+/g, "")), false, `${nome}: "${texto.slice(0, 80)}"`);
    }
  }
});

test("as rotas do painel e o assistente usam as mesmas funções (nada reescrito na rota)", () => {
  const raiz = new URL("../../app/api/digitais/", import.meta.url);
  const rotas = [
    "produtos/route.ts",
    "produtos/[id]/route.ts",
    "produtos/[id]/entregaveis/route.ts",
    "cursos/[id]/aulas/[aulaId]/route.ts",
    "arquivos/route.ts",
    "arquivos/[id]/concluir/route.ts",
    "lives/route.ts",
    "lives/[id]/route.ts",
    "alunos/route.ts",
    "configuracoes/route.ts",
    "entregas/[pedidoId]/route.ts",
    "visao-geral/route.ts",
  ];
  for (const rota of rotas) {
    const fonte = readFileSync(new URL(rota, raiz), "utf8");
    assert.match(fonte, /@\/lib\/digitais\/servidor\/acoes\//, rota);
    assert.equal(/admin\s*\.from\(/.test(fonte), false, `${rota} ainda lê o banco direto`);
  }
});

test("as ferramentas novas estão registradas e a regra das instruções fala delas", () => {
  const indice = readFileSync(new URL("index.ts", pasta), "utf8");
  assert.match(indice, /\.\.\.FERRAMENTAS_DE_DIGITAIS/);
  assert.match(indice, /pedir_video/);
  assert.match(indice, /ver_area_digital/);
});
