import { describe, expect, it } from "vitest";
import { getDummyHash, hashPassword, verifyPassword } from "@/server/auth/password";
import { generateSessionToken, hashSessionToken, isWellFormedToken } from "@/server/auth/tokens";

describe("contraseñas (Argon2id)", () => {
  it("genera hashes Argon2id con sal distinta y verifica", async () => {
    const a = await hashPassword("Chesco-2026-ok");
    const b = await hashPassword("Chesco-2026-ok");
    expect(a.startsWith("$argon2id$")).toBe(true);
    expect(a).toContain("m=19456,t=2,p=1");
    expect(a).not.toBe(b);
    expect(await verifyPassword(a, "Chesco-2026-ok")).toBe(true);
    expect(await verifyPassword(a, "otra-clave-1")).toBe(false);
  });

  it("un hash corrupto no lanza: se trata como contraseña incorrecta", async () => {
    expect(await verifyPassword("no-es-un-hash", "x")).toBe(false);
  });

  it("el hash ficticio para igualar tiempos es válido", async () => {
    expect((await getDummyHash()).startsWith("$argon2id$")).toBe(true);
  });
});

describe("tokens de sesión", () => {
  it("256 bits en base64url, únicos", () => {
    const a = generateSessionToken();
    const b = generateSessionToken();
    expect(isWellFormedToken(a)).toBe(true);
    expect(a).not.toBe(b);
  });

  it("se guarda un HMAC, no el token; depende del secreto", () => {
    const token = generateSessionToken();
    const h1 = hashSessionToken(token, "secret-a".repeat(5));
    expect(h1).toMatch(/^[0-9a-f]{64}$/);
    expect(h1).not.toContain(token);
    expect(hashSessionToken(token, "secret-a".repeat(5))).toBe(h1);
    expect(hashSessionToken(token, "secret-b".repeat(5))).not.toBe(h1);
  });

  it("descarta tokens mal formados sin consultar la base", () => {
    expect(isWellFormedToken("")).toBe(false);
    expect(isWellFormedToken("x".repeat(43) + "'")).toBe(false);
    expect(isWellFormedToken("a".repeat(44))).toBe(false);
  });
});
