import { test } from 'node:test';
import assert from 'node:assert/strict';
import {
  getCachedClientId,
  cacheClientId,
  invalidateCachedClient,
  parseOidcCallbackParams,
} from './oidcState';

const installStorage = (): Map<string, string> => {
  const store = new Map<string, string>();
  (globalThis as { localStorage?: unknown }).localStorage = {
    getItem: (k: string) => (store.has(k) ? store.get(k) : null),
    setItem: (k: string, v: string) => {
      store.set(k, String(v));
    },
    removeItem: (k: string) => {
      store.delete(k);
    },
  };
  return store;
};

test('registration cache: get / put / invalidate, scoped by issuer + redirectUri', () => {
  installStorage();
  assert.equal(getCachedClientId('iss', 'rd'), undefined);
  cacheClientId('iss', 'client-1', 'rd');
  assert.equal(getCachedClientId('iss', 'rd'), 'client-1');
  assert.equal(getCachedClientId('iss', 'other-redirect'), undefined); // redirect mismatch = miss
  assert.equal(getCachedClientId('iss2', 'rd'), undefined); // different issuer = miss
  invalidateCachedClient('iss');
  assert.equal(getCachedClientId('iss', 'rd'), undefined);
  invalidateCachedClient('absent'); // no-op, no throw
});

test('registration cache tolerates corrupt storage', () => {
  const store = installStorage();
  store.set('cinny_oidc_dynamic_clients', '{ not json');
  assert.equal(getCachedClientId('iss', 'rd'), undefined);
  cacheClientId('iss', 'c', 'rd');
  assert.equal(getCachedClientId('iss', 'rd'), 'c');
});

test('parseOidcCallbackParams classifies success / error / invalid', () => {
  assert.deepEqual(parseOidcCallbackParams('?code=abc&state=xyz'), {
    kind: 'success',
    code: 'abc',
    state: 'xyz',
  });
  assert.deepEqual(parseOidcCallbackParams('?error=access_denied&error_description=nope'), {
    kind: 'error',
    error: 'access_denied',
    errorDescription: 'nope',
  });
  assert.deepEqual(parseOidcCallbackParams('?error=bad'), {
    kind: 'error',
    error: 'bad',
    errorDescription: undefined,
  });
  assert.deepEqual(parseOidcCallbackParams('?code=only'), { kind: 'invalid' });
  assert.deepEqual(parseOidcCallbackParams(''), { kind: 'invalid' });
});
