import { describe, it, expect } from "vitest";
import { config } from "../config/env";

describe("env validation", () => {
  it("has numeric port within valid range", () => {
    expect(typeof config.port).toBe("number");
    expect(config.port).toBeGreaterThan(0);
    expect(config.port).toBeLessThanOrEqual(65535);
  });

  it("has JWT_SECRET defined", () => {
    expect(config.jwt.secret).toBeTruthy();
    expect(config.jwt.secret.length).toBeGreaterThanOrEqual(32);
  });

  it("has TOTP_ENCRYPTION_KEY defined", () => {
    expect(config.totp.encryptionKey).toBeTruthy();
    expect(config.totp.encryptionKey.length).toBeGreaterThanOrEqual(32);
  });

  it("has positive JWT expiry values", () => {
    expect(config.jwt.accessTokenExpiry).toBeGreaterThan(0);
    expect(config.jwt.refreshTokenSessionExpiry).toBeGreaterThan(0);
    expect(config.jwt.refreshTokenRememberExpiry).toBeGreaterThan(0);
  });

  it("has positive maxUploadSize", () => {
    expect(config.nas.maxUploadSize).toBeGreaterThan(0);
  });

  it("has DATABASE_URL defined", () => {
    expect(config.db.url).toBeTruthy();
  });
});

describe("env validation — failure path", () => {
  // The config singleton runs its validation at module-load time and is then
  // cached by the module system, so we cannot re-import it with bad env to
  // observe a throw without complex module-registry resetting. Instead we test
  // the exact predicates config/env.ts uses to reject bad input — this is the
  // logic that protects the boot, and the loaded config above proves the
  // happy path. (Predicates kept in sync with src/config/env.ts.)
  const HEX64_RE = /^[0-9a-fA-F]{64}$/;

  it("rejects a too-short / non-hex JWT_SECRET", () => {
    expect(HEX64_RE.test("short")).toBe(false);
    expect(HEX64_RE.test("a".repeat(63))).toBe(false); // one char short
    expect(HEX64_RE.test("z".repeat(64))).toBe(false); // 64 chars, not hex
    // The real config's secret must pass the very same check.
    expect(HEX64_RE.test(config.jwt.secret)).toBe(true);
  });

  it("rejects an out-of-range or non-numeric PORT", () => {
    const portValid = (p: number) => !Number.isNaN(p) && p >= 1 && p <= 65535;
    expect(portValid(parseInt("0", 10))).toBe(false);
    expect(portValid(parseInt("70000", 10))).toBe(false);
    expect(portValid(parseInt("notaport", 10))).toBe(false); // NaN
    expect(portValid(config.port)).toBe(true);
  });

  it("rejects a non-positive ACCESS_TOKEN_EXPIRY", () => {
    const expiryValid = (n: number) => !Number.isNaN(n) && n > 0;
    expect(expiryValid(0)).toBe(false);
    expect(expiryValid(-1)).toBe(false);
    expect(expiryValid(parseInt("oops", 10))).toBe(false); // NaN
    expect(expiryValid(config.jwt.accessTokenExpiry)).toBe(true);
  });
});
