const BASE = '/api/experience';

async function request(method: string, path: string, body?: unknown): Promise<Response> {
  const res = await fetch(`${BASE}${path}`, {
    method,
    headers: body ? { 'Content-Type': 'application/json' } : undefined,
    body: body ? JSON.stringify(body) : undefined,
    credentials: 'same-origin',
  });
  return res;
}

export async function initInteraction(): Promise<void> {
  const res = await request('PUT', '', { interactionEvent: 'SignIn' });
  if (!res.ok) {
    const err = await res.json().catch(() => ({}));
    throw new Error(err.message || `Failed to initialize sign-in (${res.status})`);
  }
}

export async function verifyPassword(
  username: string,
  password: string
): Promise<string> {
  const res = await request('POST', '/verification/password', {
    identifier: { type: 'username', value: username },
    password,
  });
  if (!res.ok) {
    const err = await res.json().catch(() => ({}));
    if (res.status === 422) {
      throw new Error('Invalid username or password');
    }
    throw new Error(err.message || `Authentication failed (${res.status})`);
  }
  const data = await res.json();
  return data.verificationId;
}

export async function identifyUser(verificationId: string): Promise<void> {
  const res = await request('POST', '/identification', { verificationId });
  if (!res.ok) {
    const err = await res.json().catch(() => ({}));
    throw new Error(err.message || `Identification failed (${res.status})`);
  }
}

export async function submitInteraction(): Promise<string> {
  const res = await request('POST', '/submit');
  if (!res.ok) {
    const err = await res.json().catch(() => ({}));
    throw new Error(err.message || `Submit failed (${res.status})`);
  }
  const data = await res.json();
  return data.redirectTo;
}

export async function signIn(username: string, password: string): Promise<string> {
  await initInteraction();
  const verificationId = await verifyPassword(username, password);
  await identifyUser(verificationId);
  return submitInteraction();
}
