import { test } from 'node:test';
import assert from 'node:assert/strict';
import { AuthType, IAuthData, UIAFlow } from 'matrix-js-sdk';
import {
  getSupportedUIAFlows,
  getUIACompleted,
  getUIAParams,
  getUIASession,
  getUIAErrorCode,
  getUIAError,
  getUIAFlowForStages,
  hasStageInFlows,
  requiredStageInFlows,
  getLoginTermUrl,
} from './matrix-uia';

const flows = (...stageLists: string[][]): UIAFlow[] =>
  stageLists.map((stages) => ({ stages })) as UIAFlow[];
const auth = (data: Record<string, unknown>): IAuthData => data as unknown as IAuthData;

test('getSupportedUIAFlows keeps only fully-supported flows', () => {
  const f = flows(['a', 'b'], ['a', 'c']);
  assert.deepEqual(getSupportedUIAFlows(f, ['a', 'b']), [{ stages: ['a', 'b'] }]);
  assert.deepEqual(getSupportedUIAFlows(f, ['a', 'b', 'c']), f);
  assert.deepEqual(getSupportedUIAFlows(f, ['x']), []);
});

test('getUIACompleted / Params / Session default sensibly', () => {
  assert.deepEqual(getUIACompleted(auth({ completed: ['m.login.password'] })), [
    'm.login.password',
  ]);
  assert.deepEqual(getUIACompleted(auth({})), []);
  assert.deepEqual(getUIAParams(auth({ params: { x: { y: 1 } } })), { x: { y: 1 } });
  assert.deepEqual(getUIAParams(auth({})), {});
  assert.equal(getUIASession(auth({ session: 'abc' })), 'abc');
  assert.equal(getUIASession(auth({})), undefined);
});

test('getUIAErrorCode / getUIAError read string fields only', () => {
  assert.equal(getUIAErrorCode(auth({ errcode: 'M_FORBIDDEN' })), 'M_FORBIDDEN');
  assert.equal(getUIAErrorCode(auth({ errcode: 42 })), undefined);
  assert.equal(getUIAErrorCode(auth({})), undefined);
  assert.equal(getUIAError(auth({ error: 'Bad' })), 'Bad');
  assert.equal(getUIAError(auth({})), undefined);
});

test('getUIAFlowForStages: exact match and no match', () => {
  const f = flows(['m.login.password'], ['m.login.recaptcha', 'm.login.password']);
  assert.deepEqual(getUIAFlowForStages(f, ['m.login.password']), { stages: ['m.login.password'] });
  assert.equal(getUIAFlowForStages(f, ['m.login.sso']), undefined);
});

test('getUIAFlowForStages allows a single extra m.login.dummy stage', () => {
  const f = flows(['m.login.recaptcha', AuthType.Dummy]);
  assert.deepEqual(getUIAFlowForStages(f, ['m.login.recaptcha']), {
    stages: ['m.login.recaptcha', AuthType.Dummy],
  });
  // two extra stages (more than dummy) → no match
  assert.equal(getUIAFlowForStages(flows(['a', 'b', AuthType.Dummy]), ['a']), undefined);
});

test('hasStageInFlows / requiredStageInFlows', () => {
  const f = flows(['m.login.password'], ['m.login.recaptcha', 'm.login.password']);
  assert.equal(hasStageInFlows(f, 'm.login.recaptcha'), true);
  assert.equal(hasStageInFlows(f, 'm.login.sso'), false);
  assert.equal(requiredStageInFlows(f, 'm.login.password'), true);
  assert.equal(requiredStageInFlows(f, 'm.login.recaptcha'), false);
});

test('getLoginTermUrl prefers en, else the first language', () => {
  const base = (policies: unknown) => ({ [AuthType.Terms]: { policies } });
  assert.equal(
    getLoginTermUrl(
      base({ privacy_policy: { en: { url: 'https://en' }, fr: { url: 'https://fr' } } }),
    ),
    'https://en',
  );
  assert.equal(
    getLoginTermUrl(base({ privacy_policy: { fr: { url: 'https://fr' } } })),
    'https://fr',
  );
  assert.equal(getLoginTermUrl({}), undefined);
  assert.equal(getLoginTermUrl(base(null)), undefined);
});
