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

import {
  acaoDoPlano,
  ANO_NO_MENSAL,
  ANUAL_POR_MES,
  ECONOMIA_DO_ANUAL,
  ECONOMIA_DO_ANUAL_PORCENTO,
  lerVencimento,
  nomeDoPlano,
  situacaoDaAssinatura,
  statusLibera,
} from "./assinatura.ts";

const AGORA = new Date("2026-09-18T12:00:00Z");

describe("nomeDoPlano", () => {
  it("traduz a chave do plano", () => {
    assert.equal(nomeDoPlano({ plan: "anual" }), "Anual");
    assert.equal(nomeDoPlano({ plan: "MENSAL" }), "Mensal");
    assert.equal(nomeDoPlano({ plan: "custom" }), "Personalizado");
  });

  it("sem chave, usa o nome do produto sem repetir Ktalogu", () => {
    assert.equal(nomeDoPlano({ plan: null, plan_name: "Ktalogu - Anual" }), "Anual");
    assert.equal(nomeDoPlano({ plan_name: "Ktalogu – Mensal" }), "Mensal");
    assert.equal(nomeDoPlano({ plan_name: "Parceria" }), "Parceria");
    assert.equal(nomeDoPlano(null), "Ktalogu");
  });
});

describe("statusLibera", () => {
  it("é a mesma leitura do middleware", () => {
    assert.deepEqual(statusLibera("active"), { libera: true, teste: false });
    assert.deepEqual(statusLibera("paid"), { libera: true, teste: false });
    assert.deepEqual(statusLibera("Ativo"), { libera: true, teste: false });
    assert.deepEqual(statusLibera("trial"), { libera: true, teste: true });
    assert.deepEqual(statusLibera("trialing"), { libera: true, teste: true });
    assert.deepEqual(statusLibera("inactive"), { libera: false, teste: false });
    assert.deepEqual(statusLibera("canceled"), { libera: false, teste: false });
    assert.deepEqual(statusLibera(null), { libera: false, teste: false });
  });
});

describe("situacaoDaAssinatura", () => {
  it("ativa com data no futuro conta os dias que faltam", () => {
    const r = situacaoDaAssinatura({ plan: "anual", status: "active", expires_at: "2027-02-27T17:29:46.368Z" }, AGORA);
    assert.equal(r.situacao, "ativa");
    assert.equal(r.ativa, true);
    assert.equal(r.plano, "Anual");
    assert.equal(r.diasRestantes, 163);
  });

  it("status ativo mas data passada é expirada, e o painel fecha", () => {
    const r = situacaoDaAssinatura({ plan: "mensal", status: "active", expires_at: "2026-09-01T00:00:00Z" }, AGORA);
    assert.equal(r.situacao, "expirada");
    assert.equal(r.ativa, false);
    assert.equal(r.diasRestantes, 0);
  });

  it("status inativo com data no futuro é inativa (cancelou, estornou)", () => {
    const r = situacaoDaAssinatura({ plan: "mensal", status: "refunded", expires_at: "2026-12-01T00:00:00Z" }, AGORA);
    assert.equal(r.situacao, "inativa");
    assert.equal(r.ativa, false);
  });

  it("teste libera e se apresenta como teste", () => {
    const r = situacaoDaAssinatura({ status: "trial", expires_at: "2026-09-25T12:00:00Z" }, AGORA);
    assert.equal(r.situacao, "teste");
    assert.equal(r.ativa, true);
    assert.equal(r.diasRestantes, 7);
  });

  it("vence hoje mais tarde ainda está ativa, com 1 dia", () => {
    const r = situacaoDaAssinatura({ status: "active", expires_at: "2026-09-18T23:00:00Z" }, AGORA);
    assert.equal(r.ativa, true);
    assert.equal(r.diasRestantes, 1);
  });

  it("sem status nem data é sem registro", () => {
    const r = situacaoDaAssinatura({ plan: null, status: null, expires_at: null }, AGORA);
    assert.equal(r.situacao, "sem-registro");
    assert.equal(r.ativa, false);
    assert.equal(r.venceEm, null);
    assert.equal(situacaoDaAssinatura(null, AGORA).situacao, "sem-registro");
  });

  it("data inválida não derruba a conta", () => {
    const r = situacaoDaAssinatura({ status: "active", expires_at: "sem data" }, AGORA);
    assert.equal(r.venceEm, null);
    assert.equal(r.ativa, true);
    assert.equal(r.diasRestantes, null);
  });
});

describe("economia do anual", () => {
  it("é a conta da página de preços", () => {
    /* 12 × 69,90 = 838,80; 838,80 − 597 = 241,80. */
    assert.equal(ANO_NO_MENSAL, 838.8);
    assert.equal(ECONOMIA_DO_ANUAL, 241.8);
    assert.equal(ECONOMIA_DO_ANUAL_PORCENTO, 29);
    assert.equal(ANUAL_POR_MES, 49.75);
  });
});

describe("vencimento sem fuso", () => {
  it("lê o horário do banco como UTC, não como hora local", () => {
    assert.equal(lerVencimento("2026-10-01T02:59:59")?.toISOString(), "2026-10-01T02:59:59.000Z");
    assert.equal(lerVencimento("2026-10-01T02:59:59.5")?.toISOString(), "2026-10-01T02:59:59.500Z");
  });

  it("respeita o fuso quando ele vem", () => {
    assert.equal(lerVencimento("2026-09-30T23:59:59-03:00")?.toISOString(), "2026-10-01T02:59:59.000Z");
    assert.equal(lerVencimento("2026-10-01T02:59:59+00:00")?.toISOString(), "2026-10-01T02:59:59.000Z");
    assert.equal(lerVencimento("2026-10-01T02:59:59Z")?.toISOString(), "2026-10-01T02:59:59.000Z");
  });

  it("sem data válida é nulo", () => {
    assert.equal(lerVencimento("sem data"), null);
    assert.equal(lerVencimento(""), null);
    assert.equal(lerVencimento(null), null);
  });
});

describe("o botão de pagar", () => {
  const base = { origem: "nova" as const, plano: "mensal" as const, ativa: true, renovaSozinha: false, diasRestantes: 18 };

  it("sem assinatura, é só assinar", () => {
    const a = acaoDoPlano({ ...base, origem: "nenhuma", plano: null, ativa: false, diasRestantes: 0 }, "anual");
    assert.equal(a.tipo, "assinar");
    assert.equal(a.podeComprar, true);
  });

  it("mensal escolhendo anual é upgrade, soma os dias e cancela o mensal", () => {
    const a = acaoDoPlano(base, "anual");
    assert.equal(a.tipo, "upgrade");
    assert.match(a.botao, /upgrade/i);
    assert.match(a.explicacao ?? "", /18 dias/);
  });

  it("anual com mais de 30 dias não troca para o mensal", () => {
    const a = acaoDoPlano({ ...base, plano: "anual", diasRestantes: 200 }, "mensal");
    assert.equal(a.tipo, "downgrade-bloqueado");
    assert.equal(a.podeComprar, false);
  });

  it("nos últimos 30 dias do anual, a troca para o mensal libera", () => {
    const a = acaoDoPlano({ ...base, plano: "anual", diasRestantes: 20 }, "mensal");
    assert.equal(a.tipo, "downgrade");
    assert.equal(a.podeComprar, true);
  });

  it("mesmo plano sempre deixa pagar mais um período, somando o que falta", () => {
    const mensal = acaoDoPlano({ ...base, renovaSozinha: true }, "mensal");
    assert.equal(mensal.tipo, "renovar-antes");
    assert.equal(mensal.podeComprar, true);
    assert.equal(mensal.botao, "Pagar mais um mês");
    assert.match(mensal.explicacao ?? "", /18 dias/);
    assert.match(mensal.explicacao ?? "", /renovação automática continua/);

    const anual = acaoDoPlano({ ...base, plano: "anual", diasRestantes: 300 }, "anual");
    assert.equal(anual.botao, "Renovar por mais um ano");
    assert.equal(anual.podeComprar, true);
    assert.match(anual.explicacao ?? "", /300 dias/);
    assert.doesNotMatch(anual.explicacao ?? "", /automática/);
  });

  it("cliente do plano antigo migra e é avisado de que o antigo acaba", () => {
    const a = acaoDoPlano({ ...base, origem: "antiga" }, "anual");
    assert.equal(a.tipo, "migrar");
    assert.match(a.explicacao ?? "", /preço antigo/);
  });

  it("vencido, qualquer plano é assinar", () => {
    assert.equal(acaoDoPlano({ ...base, plano: "anual", ativa: false, diasRestantes: 0 }, "mensal").tipo, "assinar");
  });
});
