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

import {
  duracaoLegivel,
  lerConfigDoCurso,
  lerLinkDeVideo,
  linkGuardado,
  quandoAbre,
  relogio,
  resumoDoConteudo,
  rotuloDaRegra,
  rotuloDeQuandoAbre,
  capituloNoTempo,
  capitulosDoTexto,
  lerCapitulos,
  segundosDoRelogio,
  textoDosCapitulos,
  cargaHorariaEmMinutos,
  textoDaCargaHoraria,
} from "./curso.ts";

test("links do YouTube viram o endereço de incorporação sem cookies", () => {
  const esperado = { provedor: "youtube", id: "dQw4w9WgXcQ", url: "https://www.youtube-nocookie.com/embed/dQw4w9WgXcQ" };
  assert.deepEqual(lerLinkDeVideo("https://www.youtube.com/watch?v=dQw4w9WgXcQ&t=10s"), esperado);
  assert.deepEqual(lerLinkDeVideo("youtu.be/dQw4w9WgXcQ"), esperado);
  assert.deepEqual(lerLinkDeVideo("https://youtube.com/shorts/dQw4w9WgXcQ"), esperado);
  assert.deepEqual(lerLinkDeVideo("https://m.youtube.com/watch?v=dQw4w9WgXcQ"), esperado);
  assert.deepEqual(lerLinkDeVideo("https://www.youtube.com/embed/dQw4w9WgXcQ"), esperado);
  assert.equal(lerLinkDeVideo("https://www.youtube.com/watch?v=curto"), null);
});

test("links do Vimeo, inclusive não listados", () => {
  assert.deepEqual(lerLinkDeVideo("https://vimeo.com/123456789"), { provedor: "vimeo", id: "123456789", url: "https://player.vimeo.com/video/123456789" });
  assert.deepEqual(lerLinkDeVideo("https://vimeo.com/123456789/abc123def0"), {
    provedor: "vimeo",
    id: "123456789:abc123def0",
    url: "https://player.vimeo.com/video/123456789?h=abc123def0",
  });
  assert.deepEqual(lerLinkDeVideo("https://player.vimeo.com/video/123456789?h=ff00aa11"), {
    provedor: "vimeo",
    id: "123456789:ff00aa11",
    url: "https://player.vimeo.com/video/123456789?h=ff00aa11",
  });
});

test("links do Panda Video", () => {
  const id = "0b0f7c8a-1234-4abc-9def-0123456789ab";
  assert.deepEqual(lerLinkDeVideo(`https://player-vz-abc123.tv.pandavideo.com.br/embed/?v=${id}`), {
    provedor: "panda",
    id,
    url: `https://player-vz-abc123.tv.pandavideo.com.br/embed/?v=${id}`,
  });
  assert.equal(lerLinkDeVideo("https://dashboard.pandavideo.com.br/videos/x"), null);
});

test("o que não é vídeo conhecido não passa", () => {
  assert.equal(lerLinkDeVideo("javascript:alert(1)"), null);
  assert.equal(lerLinkDeVideo("https://exemplo.com/video.mp4"), null);
  assert.equal(lerLinkDeVideo('<iframe src="https://youtube.com/embed/dQw4w9WgXcQ">'), null);
  assert.equal(lerLinkDeVideo(42), null);
  assert.equal(linkGuardado({ url: "https://evil.com/embed/x" }), null);
  assert.deepEqual(linkGuardado({ provedor: "youtube", id: "x", url: "https://youtu.be/dQw4w9WgXcQ" })?.id, "dQw4w9WgXcQ");
});

const INICIO = "2026-10-01T12:00:00.000Z";
const T = (iso: string) => new Date(iso).getTime();

test("módulo e aula abrem na hora certa", () => {
  const imediata = { liberacao: "imediata" as const, dias: null, em: null };
  assert.deepEqual(quandoAbre({ inicio: INICIO, modulo: imediata, agora: T(INICIO) }), { aberta: true, abreEm: null });

  const seteDias = { liberacao: "dias" as const, dias: 7, em: null };
  assert.deepEqual(quandoAbre({ inicio: INICIO, modulo: seteDias, agora: T("2026-10-05T12:00:00.000Z") }), {
    aberta: false,
    abreEm: "2026-10-08T12:00:00.000Z",
  });
  assert.equal(quandoAbre({ inicio: INICIO, modulo: seteDias, agora: T("2026-10-08T12:00:00.000Z") }).aberta, true);

  const naData = { liberacao: "data" as const, dias: null, em: "2026-11-10T03:00:00.000Z" };
  assert.equal(quandoAbre({ inicio: INICIO, modulo: naData, agora: T("2026-11-09T23:00:00.000Z") }).aberta, false);

  /* A aula nunca abre antes do módulo. */
  const aulaCedo = { liberacao: "dias" as const, dias: 2, em: null };
  assert.deepEqual(quandoAbre({ inicio: INICIO, modulo: seteDias, aula: aulaCedo, agora: T("2026-10-04T12:00:00.000Z") }).abreEm, "2026-10-08T12:00:00.000Z");
  const aulaDepois = { liberacao: "dias" as const, dias: 10, em: null };
  assert.equal(quandoAbre({ inicio: INICIO, modulo: seteDias, aula: aulaDepois, agora: T("2026-10-09T12:00:00.000Z") }).abreEm, "2026-10-11T12:00:00.000Z");
  const junto = { liberacao: "modulo" as const, dias: null, em: null };
  assert.equal(quandoAbre({ inicio: INICIO, modulo: imediata, aula: junto, agora: T(INICIO) }).aberta, true);
});

test("rótulos de quando abre", () => {
  const agora = T("2026-10-05T12:00:00.000Z");
  assert.equal(rotuloDeQuandoAbre("2026-10-08T12:00:00.000Z", agora), "abre em 3 dias");
  assert.equal(rotuloDeQuandoAbre("2026-10-06T13:00:00.000Z", agora), "abre amanhã");
  assert.equal(rotuloDeQuandoAbre("2026-10-05T22:00:00.000Z", agora), "abre hoje às 19:00");
  /* 22h em Brasília, abre às 10h do dia seguinte: "amanhã", não "às 10:00". */
  assert.equal(rotuloDeQuandoAbre("2026-10-06T13:00:00.000Z", T("2026-10-06T01:00:00.000Z")), "abre amanhã");
  assert.equal(rotuloDeQuandoAbre("2026-10-01T12:00:00.000Z", agora), null);
  assert.equal(rotuloDaRegra({ liberacao: "dias", dias: 7, em: null }), "abre 7 dias depois da compra");
  assert.equal(rotuloDaRegra({ liberacao: "dias", dias: 1, em: null }), "abre 1 dia depois da compra");
  assert.equal(rotuloDaRegra({ liberacao: "data", dias: null, em: "2026-11-10T03:00:00.000Z" }), "abre em 10/11/2026");
  assert.equal(rotuloDaRegra({ liberacao: "imediata", dias: null, em: null }), null);
});

test("durações", () => {
  assert.equal(relogio(1102), "18:22");
  assert.equal(relogio(4380), "1:13:00");
  assert.equal(relogio(null), "0:00");
  assert.equal(duracaoLegivel(24000), "6h 40min");
  assert.equal(duracaoLegivel(840), "14 min");
  assert.equal(duracaoLegivel(3600), "1h");
});

test("o resumo público só leva aulas publicadas, e módulo vazio some", () => {
  const resumo = resumoDoConteudo(
    [
      { id: "m1", titulo: "Boas-vindas", descricao: null, liberacao: "imediata", dias: null, em: null },
      { id: "m2", titulo: "Vazio", descricao: null, liberacao: "imediata", dias: null, em: null },
      { id: "m3", titulo: "Camisetas", descricao: "Tecido", liberacao: "dias", dias: 7, em: null },
    ],
    [
      { id: "a1", moduloId: "m1", titulo: "Como aproveitar", tipo: "video", duracaoS: 250, previaGratis: true, publicada: true },
      { id: "a2", moduloId: "m1", titulo: "Rascunho", tipo: "video", duracaoS: 999, previaGratis: false, publicada: false },
      { id: "a3", moduloId: "m3", titulo: "Lista", tipo: "texto", duracaoS: null, previaGratis: false, publicada: true },
      { id: "a4", moduloId: "m3", titulo: "Prensa", tipo: "video", duracaoS: 1102, previaGratis: false, publicada: true },
    ],
    2
  );
  assert.equal(resumo.modulos.length, 2);
  assert.equal(resumo.aulas, 3);
  assert.equal(resumo.duracaoS, 1352);
  assert.equal(resumo.materiais, 2);
  assert.equal(resumo.modulos[1].abre, "abre 7 dias depois da compra");
});

test("a config do curso é lida com segurança", () => {
  const lida = lerConfigDoCurso({
    aprendizados: ["  Escolher a impressora ", "", 42, "x".repeat(300)],
    professor: { nome: "Paula Reis", foto: "http://inseguro.com/a.png", destaque: "Dona da gráfica", bio: "Bio" },
    apresentacao: { link: { url: "https://youtu.be/dQw4w9WgXcQ" } },
    garantiaDias: 7,
    conteudo: { modulos: [{ id: "m1", titulo: "M", aulas: [{ id: "a1", titulo: "A", tipo: "hack", duracaoS: -3 }] }], aulas: 1 },
  });
  assert.deepEqual(lida.aprendizados, ["Escolher a impressora", "x".repeat(140)]);
  assert.deepEqual(lida.professor, { nome: "Paula Reis", foto: null, destaque: "Dona da gráfica", bio: "Bio" });
  assert.deepEqual(lida.apresentacao, { link: { provedor: "youtube", id: "dQw4w9WgXcQ", url: "https://www.youtube-nocookie.com/embed/dQw4w9WgXcQ" } });
  assert.equal(lida.garantiaDias, 7);
  assert.equal(lida.conteudo.modulos[0].aulas[0].tipo, "video");
  assert.equal(lida.conteudo.modulos[0].aulas[0].duracaoS, null);
  assert.deepEqual(lerConfigDoCurso(null).conteudo, { modulos: [], aulas: 0, duracaoS: 0, materiais: 0 });
  assert.equal(lerConfigDoCurso({ apresentacao: { arquivoId: "nao-e-uuid" } }).apresentacao, null);
});

test("capítulos: texto do editor, ordem, repetidos e o capítulo do momento", () => {
  const { capitulos, ignoradas } = capitulosDoTexto("12:40 Prensa 5 em 1\n0:00 Abertura\nsem tempo aqui\n1:02:03 - Final\n12:40 repetido");
  assert.deepEqual(capitulos, [
    { inicioS: 0, titulo: "Abertura" },
    { inicioS: 760, titulo: "Prensa 5 em 1" },
    { inicioS: 3723, titulo: "Final" },
  ]);
  assert.equal(ignoradas, 1);
  assert.equal(textoDosCapitulos(capitulos), "0:00 Abertura\n12:40 Prensa 5 em 1\n1:02:03 Final");
  assert.equal(capituloNoTempo(capitulos, 800)?.titulo, "Prensa 5 em 1");
  assert.equal(capituloNoTempo(capitulos, 0)?.titulo, "Abertura");
  assert.equal(segundosDoRelogio("1:75"), null);
  assert.deepEqual(lerCapitulos([{ inicioS: -1, titulo: "x" }, { inicioS: 5, titulo: "" }, "lixo"]), []);
});

test("certificado do curso: ligado por padrão, carga horária da loja ou dos vídeos", () => {
  assert.deepEqual(lerConfigDoCurso({}).certificado, { emitir: true, cargaHoras: null });
  assert.deepEqual(lerConfigDoCurso({ certificado: { emitir: false, cargaHoras: "20" } }).certificado, { emitir: false, cargaHoras: 20 });
  assert.equal(lerConfigDoCurso({ certificado: { cargaHoras: 0 } }).certificado.cargaHoras, null);
  assert.equal(cargaHorariaEmMinutos({ cargaHoras: 20 }, 999), 1200);
  assert.equal(cargaHorariaEmMinutos({ cargaHoras: null }, 24001), 401);
  assert.equal(textoDaCargaHoraria(1200), "20 horas");
  assert.equal(textoDaCargaHoraria(60), "1 hora");
  assert.equal(textoDaCargaHoraria(400), "6h 40min");
  assert.equal(textoDaCargaHoraria(45), "45 min");
});
