import { api, setTokens } from './http';

export interface AuthTokenData {
  access_token: string;
  refresh_token: string;
  expires_in: number;
  uid: string;
  token_type: string;
}

export interface LoginData extends Partial<AuthTokenData> {
  mfa_required?: boolean;
  mfa_challenge_id?: string;
  mfa_expires_in?: number;
}

export interface RegisterData {
  challenge_id: string;
  expires_in: number;
  uid: string;
}

function applyAuthTokens(data: AuthTokenData) {
  setTokens(data.access_token, data.refresh_token);
  localStorage.setItem('uid', data.uid);
}

export async function login(tenantSlug: string, email: string, password: string) {
  const data = await api<LoginData>('/api/v1/auth/login', {
    auth: false,
    method: 'POST',
    body: JSON.stringify({ tenant_slug: tenantSlug, email, password }),
  });
  if (data.mfa_required) {
    return data;
  }
  applyAuthTokens(data as AuthTokenData);
  return data;
}

export async function loginMfaConfirm(
  tenantSlug: string,
  challengeId: string,
  code: string,
) {
  const data = await api<AuthTokenData>('/api/v1/auth/login/mfa', {
    auth: false,
    method: 'POST',
    body: JSON.stringify({
      tenant_slug: tenantSlug,
      challenge_id: challengeId,
      code,
    }),
  });
  applyAuthTokens(data);
  return data;
}

export async function register(body: {
  tenant_slug: string;
  invite_code: string;
  email: string;
  password: string;
  display_name?: string;
  language?: string;
}) {
  return api<RegisterData>('/api/v1/auth/register', {
    auth: false,
    method: 'POST',
    body: JSON.stringify({
      ...body,
      accept_terms_version: '2025-01-01',
      marketing_opt_in: false,
    }),
  });
}

export async function registerConfirm(
  tenantSlug: string,
  challengeId: string,
  code: string,
) {
  const data = await api<AuthTokenData>('/api/v1/auth/register/confirm', {
    auth: false,
    method: 'POST',
    body: JSON.stringify({
      tenant_slug: tenantSlug,
      challenge_id: challengeId,
      code,
    }),
  });
  setTokens(data.access_token, data.refresh_token);
  localStorage.setItem('uid', data.uid);
  return data;
}

export async function registerResend(tenantSlug: string, challengeId: string) {
  return api<RegisterData>('/api/v1/auth/register/resend', {
    auth: false,
    method: 'POST',
    body: JSON.stringify({ tenant_slug: tenantSlug, challenge_id: challengeId }),
  });
}

export async function registerResume(tenantSlug: string, email: string) {
  return api<RegisterData>('/api/v1/auth/register/resume', {
    auth: false,
    method: 'POST',
    body: JSON.stringify({
      tenant_slug: tenantSlug,
      email,
    }),
  });
}

export interface PasswordChallengeData {
  challenge_id: string;
  expires_in: number;
}

export async function passwordForgot(tenantSlug: string, email: string) {
  return api<PasswordChallengeData>('/api/v1/auth/password/forgot', {
    auth: false,
    method: 'POST',
    body: JSON.stringify({ tenant_slug: tenantSlug, email }),
  });
}

export async function passwordReset(
  tenantSlug: string,
  challengeId: string,
  code: string,
  newPassword: string,
) {
  return api<{ ok: boolean }>('/api/v1/auth/password/reset', {
    auth: false,
    method: 'POST',
    body: JSON.stringify({
      tenant_slug: tenantSlug,
      challenge_id: challengeId,
      code,
      new_password: newPassword,
    }),
  });
}

export async function logout() {
  try {
    await api('/api/v1/auth/logout', { method: 'POST', body: '{}' });
  } finally {
    /* always clear local */
  }
}

export type FederatedProvider = 'google' | 'ldap';

export interface SocialStartData {
  oauth_url: string;
  session_id: string;
  expires_in: number;
}

export async function loginSocialStart(
  tenantSlug: string,
  provider: FederatedProvider,
  redirectUri: string,
) {
  return api<SocialStartData>('/api/v1/auth/login/social/start', {
    auth: false,
    method: 'POST',
    body: JSON.stringify({
      tenant_slug: tenantSlug,
      provider,
      redirect_uri: redirectUri,
    }),
  });
}

export async function loginSocialCallback(code: string, state: string) {
  const qs = new URLSearchParams({ code, state });
  const data = await api<LoginData>(
    `/api/v1/auth/login/social/callback?${qs.toString()}`,
    { auth: false },
  );
  if (data.mfa_required) {
    return data;
  }
  if (data.access_token && data.refresh_token && data.uid) {
    applyAuthTokens(data as AuthTokenData);
  }
  return data;
}

export async function registerSocialStart(body: {
  tenant_slug: string;
  invite_code: string;
  provider: FederatedProvider;
  redirect_uri: string;
  language?: string;
}) {
  return api<SocialStartData>('/api/v1/auth/register/social/start', {
    auth: false,
    method: 'POST',
    body: JSON.stringify({
      ...body,
      accept_terms_version: '2025-01-01',
      marketing_opt_in: false,
    }),
  });
}

export async function registerSocialCallback(code: string, state: string) {
  const qs = new URLSearchParams({ code, state });
  const data = await api<AuthTokenData>(
    `/api/v1/auth/register/social/callback?${qs.toString()}`,
    { auth: false },
  );
  applyAuthTokens(data);
  return data;
}

export function startOAuthRedirect(oauthUrl: string) {
  window.location.assign(oauthUrl);
}

export async function refreshToken() {
  const refresh = localStorage.getItem('refresh_token');
  if (!refresh) throw new Error('無 refresh token');
  const data = await api<AuthTokenData>('/api/v1/auth/token/refresh', {
    auth: false,
    method: 'POST',
    body: JSON.stringify({ refresh_token: refresh }),
  });
  setTokens(data.access_token, data.refresh_token);
  localStorage.setItem('uid', data.uid);
  return data;
}
