import { describe, expect, test } from "bun:test";
import {
  clearJwtCookie,
  createAccessToken,
  createRefreshToken,
  createTokenPair,
  extractBearerToken,
  hasScopes,
  jwtCookie,
  readJwtCookie,
  tokenScopes,
  verifyAccessToken,
  verifyRefreshToken,
} from "../src/index.ts";

const secret = "a-long-jwt-package-helper-test-secret";

describe("JWT helper kit", () => {
  test("creates and verifies typed access and refresh tokens", async () => {
    const access = await createAccessToken("user-1", secret, {
      scopes: ["profile:read", "profile:write"],
      expiresIn: 60,
      now: 100,
    });
    const refresh = await createRefreshToken("user-1", secret, {
      family: "family-1",
      expiresIn: 600,
      now: 100,
    });
    const accessClaims = await verifyAccessToken(access, secret, { now: 120 });
    const refreshClaims = await verifyRefreshToken(refresh, secret, { now: 120 });
    expect(hasScopes(accessClaims, ["profile:read", "profile:write"])).toBe(true);
    expect(tokenScopes(accessClaims)).toEqual(["profile:read", "profile:write"]);
    expect(refreshClaims.family).toBe("family-1");
  });

  test("creates complete access and refresh pairs", async () => {
    const pair = await createTokenPair("user-1", {
      accessSecret: secret,
      accessExpiresIn: 60,
      refreshExpiresIn: 600,
      scopes: ["profile:read"],
      family: "family-2",
      accessOptions: { now: 100 },
      refreshOptions: { now: 100 },
    });
    expect((await verifyAccessToken(pair.accessToken, secret, { now: 120 })).type).toBe("access");
    expect((await verifyRefreshToken(pair.refreshToken, secret, { now: 120 })).family).toBe(
      "family-2",
    );
  });

  test("extracts bearer and cookie tokens from supported sources", () => {
    expect(extractBearerToken("Bearer abc")).toBe("abc");
    expect(extractBearerToken(new Headers({ authorization: "bearer xyz" }))).toBe("xyz");
    expect(readJwtCookie("other=x; __Host-wrn_token=abc%20123")).toBe("abc 123");
  });

  test("enforces secure cookie invariants", () => {
    expect(jwtCookie("token")).toContain("__Host-wrn_token=token");
    expect(clearJwtCookie()).toContain("Max-Age=0");
    expect(() => jwtCookie("token", { path: "/auth" })).toThrow("__Host-");
    expect(() => jwtCookie("token", { name: "bad;name" })).toThrow("cookie name");
    expect(() => jwtCookie("token", { name: "token", sameSite: "None", secure: false })).toThrow(
      "SameSite=None",
    );
  });
});
