import { describe, it, expect } from 'vitest';
import * as jose from 'jose';
import { discoverOidcConfig, buildAuthorizationUrl, verifyIdToken } from './oidcClient';

// Hits real CSC infrastructure -- confirms Keycloak's discovery document
// actually looks the way this client assumes.
describe('discoverOidcConfig (live)', () => {
  it('discovers the real CSC Keycloak realm', async () => {
    const discovery = await discoverOidcConfig('https://keycloak.csclub.uwaterloo.ca/realms/csc');
    expect(discovery.issuer).toBe('https://keycloak.csclub.uwaterloo.ca/realms/csc');
    expect(discovery.authorization_endpoint).toContain('/protocol/openid-connect/auth');
    expect(discovery.token_endpoint).toContain('/protocol/openid-connect/token');
    expect(discovery.jwks_uri).toContain('/protocol/openid-connect/certs');
  }, 10000);
});

describe('buildAuthorizationUrl', () => {
  it('includes client_id, redirect_uri, state, and openid scopes', () => {
    const url = buildAuthorizationUrl(
      {
        authorization_endpoint: 'https://keycloak.example/auth',
        token_endpoint: 'https://keycloak.example/token',
        jwks_uri: 'https://keycloak.example/certs',
        issuer: 'https://keycloak.example',
      },
      { issuerUrl: 'https://keycloak.example', clientId: 'eventer', clientSecret: 'secret' },
      'http://localhost:3001/callback',
      'abc123'
    );
    const parsed = new URL(url);
    expect(parsed.searchParams.get('client_id')).toBe('eventer');
    expect(parsed.searchParams.get('redirect_uri')).toBe('http://localhost:3001/callback');
    expect(parsed.searchParams.get('state')).toBe('abc123');
    expect(parsed.searchParams.get('scope')).toBe('openid profile email');
  });
});

describe('verifyIdToken', () => {
  it('verifies a real RS256 token and extracts username/email', async () => {
    const { publicKey, privateKey } = await jose.generateKeyPair('RS256');
    const idToken = await new jose.SignJWT({ preferred_username: 'j47ho', email: 'j47ho@uwaterloo.ca' })
      .setProtectedHeader({ alg: 'RS256' })
      .setIssuer('https://keycloak.example')
      .setAudience('eventer')
      .setExpirationTime('5m')
      .sign(privateKey);

    const session = await verifyIdToken(
      idToken,
      async () => publicKey,
      'https://keycloak.example',
      'eventer'
    );
    expect(session).toEqual({ username: 'j47ho', email: 'j47ho@uwaterloo.ca' });
  });

  it('rejects a token with the wrong audience', async () => {
    const { publicKey, privateKey } = await jose.generateKeyPair('RS256');
    const idToken = await new jose.SignJWT({ preferred_username: 'j47ho' })
      .setProtectedHeader({ alg: 'RS256' })
      .setIssuer('https://keycloak.example')
      .setAudience('someone-else')
      .setExpirationTime('5m')
      .sign(privateKey);

    await expect(
      verifyIdToken(idToken, async () => publicKey, 'https://keycloak.example', 'eventer')
    ).rejects.toThrow();
  });
});
