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

import { createGoogleOidcVerifier } from "./google-oidc.js";

const NOW = Date.UTC(2026, 7, 2, 12, 0, 0);
const CONFIG = {
  audience: "https://verifier.example.com/internal/google-play/rtdn",
  serviceAccounts: ["play-events@example-project.iam.gserviceaccount.com"],
};

test("OIDC verifier accepts only a Google token bound to the exact audience and service account", async () => {
  let options;
  const verifier = createGoogleOidcVerifier({
    client: {
      async verifyIdToken(value) {
        options = value;
        return { getPayload: () => validPayload() };
      },
    },
    now: () => NOW,
  });

  assert.deepEqual(await verifier.verifyRequest(request("signed-token"), CONFIG), {
    serviceAccount: "play-events@example-project.iam.gserviceaccount.com",
  });
  assert.deepEqual(options, {
    idToken: "signed-token",
    audience: CONFIG.audience,
  });
});

test("OIDC verifier fails closed for malformed authorization and unsafe claims", async (t) => {
  const cases = [
    ["missing bearer token", request(), validPayload()],
    ["wrong scheme", request("signed-token", "Basic"), validPayload()],
    ["wrong issuer", request("signed-token"), validPayload({ iss: "https://issuer.example" })],
    ["wrong audience", request("signed-token"), validPayload({ aud: "https://other.example" })],
    ["unverified email", request("signed-token"), validPayload({ email_verified: false })],
    ["unlisted account", request("signed-token"), validPayload({ email: "other@example-project.iam.gserviceaccount.com" })],
    ["expired", request("signed-token"), validPayload({ exp: Math.floor(NOW / 1000) })],
    ["future token", request("signed-token"), validPayload({ iat: Math.floor(NOW / 1000) + 301 })],
  ];
  for (const [name, req, payload] of cases) {
    await t.test(name, async () => {
      const verifier = createGoogleOidcVerifier({
        client: { async verifyIdToken() { return { getPayload: () => payload }; } },
        now: () => NOW,
      });
      await assert.rejects(verifier.verifyRequest(req, CONFIG), (error) => {
        assert.equal(error.status, 401);
        assert.equal(error.code, "unauthorized");
        assert.equal(JSON.stringify(error).includes("signed-token"), false);
        return true;
      });
    });
  }
});

test("OIDC library failures are reduced to the fixed authorization error", async () => {
  const verifier = createGoogleOidcVerifier({
    client: { async verifyIdToken() { throw new Error("raw token verification detail"); } },
    now: () => NOW,
  });
  await assert.rejects(verifier.verifyRequest(request("private-token"), CONFIG), (error) => {
    assert.equal(error.status, 401);
    assert.equal(error.code, "unauthorized");
    assert.equal(error.message.includes("private-token"), false);
    assert.equal(error.message.includes("raw token"), false);
    return true;
  });
});

function request(token, scheme = "Bearer") {
  return { headers: token ? { authorization: `${scheme} ${token}` } : {} };
}

function validPayload(overrides = {}) {
  return {
    iss: "https://accounts.google.com",
    aud: CONFIG.audience,
    email: CONFIG.serviceAccounts[0],
    email_verified: true,
    iat: Math.floor(NOW / 1000) - 60,
    exp: Math.floor(NOW / 1000) + 3600,
    ...overrides,
  };
}
