user/account.ts

/**
 * @module Accounts
 */
import { HttpClient } from '../../infrastructure/http/HttpClient'
import { HttpError } from '../../infrastructure/http/interfaces/HttpError'
import { globalConfig } from '../config.js'
import { clearAllCachedData } from '../dataContext.js'
import { Onboarding } from './onboarding'
import { AuthResponse } from './types'

/**
 * @param {string} email - The email address to check the account status for.
 * @returns {Promise<{requires_setup: boolean}>} - A promise that resolves to an object indicating whether account setup is required, or an HttpError if the request fails.
 *
 * @throws {HttpError} - Throws HttpError if the request fails.
 */
export async function status(email: string): Promise<{ requires_setup: boolean }> {
  const httpClient = new HttpClient(globalConfig.baseUrl)
  return await httpClient.post<{ requires_setup: boolean }>(
    `/api/user-management-system/v1/accounts/${encodeURIComponent(email)}/status`,
    []
  )
}

/**
 * @param {string} email - The email address to send the account setup email to.
 * @returns {Promise<void>} - A promise that resolves when the email is sent or an HttpError if the request fails.
 * @throws {HttpError} - Throws HttpError if the request fails.
 */
export async function sendAccountSetupEmail(email: string): Promise<void> {
  const httpClient = new HttpClient(globalConfig.baseUrl)
  return httpClient.post<void>(
    `/api/user-management-system/v1/accounts/${encodeURIComponent(email)}/send-setup-email`,
    {}
  )
}

export interface AccountSetupProps {
  email: string
  password: string
  passwordConfirmation: string
  token?: string
  revenuecatAppUserId?: string
  deviceName?: string
  from?: string
  hasSkippedPaywall?: boolean
}

export interface AccountSetupResponse {
  auth: AuthResponse
  onboarding: Onboarding
  product_brand?: string
}

/**
 * @param {Object} props - The parameters for setting up the account.
 * @property {string} email - The email address for the account.
 * @property {string} password - The new password for the account.
 * @property {string} passwordConfirmation - The confirmation of the new password.
 * @property {string} [token] - The token sent to the user's email for verification. Required for web requests
 * @property {string} [revenuecatAppUserId] - The RevenueCat App User ID for MA environments. Required for MA requests
 * @property {string} [deviceName] - The device name for MA environments. Required for MA requests
 *
 * @returns {Promise<AccountSetupResponse>} - A promise that resolves when the account setup is complete or an HttpError if the request fails.
 * @throws {Error} - Throws an error if required parameters are missing based on the environment.
 * @throws {HttpError} - Throws an HttpError if the HTTP request fails.
 */
export async function setupAccount(props: AccountSetupProps): Promise<AccountSetupResponse> {
  const httpClient = new HttpClient(globalConfig.baseUrl)
  if (
    !props.hasSkippedPaywall &&
    (!globalConfig.isMA || props.from === 'mobile-ios-app') &&
    !props.token
  ) {
    throw new Error('Token is required for non-MA environments')
  }

  const res = await httpClient.post<AccountSetupResponse>(
    `/api/user-management-system/v1/accounts`,
    {
      email: props.email,
      password: props.password,
      password_confirmation: props.passwordConfirmation,
      token: props.token,
      from: props.from,
      has_skipped_paywall: props.hasSkippedPaywall,
      mobile_app_id: props.revenuecatAppUserId,
    }
  )

  return res
}

/**
 * @param {string} email - The email address to send the password reset email to.
 * @returns {Promise<void>} - A promise that resolves when the email change request is made.
 * @throws {HttpError} - Throws HttpError if the request fails.
 */
export async function sendPasswordResetEmail(email: string): Promise<void> {
  const httpClient = new HttpClient(globalConfig.baseUrl)
  return httpClient.post(`/api/user-management-system/v1/accounts/password/reset-email`, {
    email,
  })
}

export interface PasswordResetProps {
  email: string
  password: string
  passwordConfirmation: string
  token: string
}
/**
 * @param {Object} params - The parameters for resetting the password.
 * @property {string} email - The email address for the account.
 * @property {string} password - The new password for the account.
 * @property {string} passwordConfirmation - The confirmation of the new password.
 * @property {string} token - The token sent to the user's email for verification.
 * @returns {Promise<void>} - A promise that resolves when the password reset is complete or an HttpError if the request fails.
 * @throws {HttpError} - Throws an HttpError if the HTTP request fails.
 */
export async function resetPassword({
  email,
  password,
  passwordConfirmation,
  token,
}: PasswordResetProps): Promise<void> {
  const httpClient = new HttpClient(globalConfig.baseUrl)
  return httpClient.post(`/api/user-management-system/v1/accounts/password/reset`, {
    email,
    password,
    password_confirmation: passwordConfirmation,
    token,
  })
}

/**
 * @param {string} email - The new email address to set for the user.
 * @param {string} password - The current password of the user for verification.
 * @returns {Promise<void>} - A promise that resolves when the email change request is made.
 * @throws {HttpError} - Throws HttpError if the request fails.
 */
export async function requestEmailChange(email: string, password: string): Promise<void> {
  const apiUrl = `/api/user-management-system/v1/accounts/${globalConfig.sessionConfig.userId}/email-change`
  const httpClient = new HttpClient(globalConfig.baseUrl, globalConfig.sessionConfig.token)
  return httpClient.post(apiUrl, { email, password })
}

/**
 * @param {string} token - The token sent to the user's email for verification.
 * @returns {Promise<void>} - A promise that resolves when the email change is confirmed.
 * @throws {HttpError} - Throws HttpError if the request fails.
 */
export async function confirmEmailChange(token: string): Promise<void> {
  const apiUrl = `/api/user-management-system/v1/accounts/email-change/confirm`
  const httpClient = new HttpClient(globalConfig.baseUrl, globalConfig.sessionConfig.token)
  return httpClient.post(apiUrl, { token })
}

/**
 * @param {number} userId - The ID of the user account to delete.
 * @returns {Promise<void>} - A promise that resolves with the anonymized user data or an HttpError if the request fails.
 */
export async function deleteAccount(userId: number): Promise<void> {
  const apiUrl = `/api/user-management-system/v1/users/${userId}`
  const httpClient = new HttpClient(globalConfig.baseUrl, globalConfig.sessionConfig.token)
  await httpClient.delete(apiUrl)

  // Clear all locally cached data to prevent data leakage between users
  await clearAllCachedData()
}

/**
 * Calls a public API endpoint to get the number of active users.
 *
 * @returns {Promise<number>} - A promise that resolves to the number of active users.
 * @throws {HttpError} - Throws HttpError if the request fails.
 */
export async function numberOfActiveUsers(): Promise<number> {
  const apiUrl = `/api/user-management-system/v1/accounts/active/count`
  const httpClient = new HttpClient(globalConfig.baseUrl)
  const response = await httpClient.get<{ active_users: number }>(apiUrl)
  return response.active_users
}

export interface UserResource {
  id: number
  email: string
  display_name: string
  first_name: string
  last_name: string
  permission_level: string
  use_student_view: boolean
  is_admin: boolean
  show_admin_toggle: boolean
  [key: string]: any // Allow additional properties from the API
}

/**
 * Toggles the student view mode for admin users.
 * When enabled, admins see the platform as a regular student would.
 *
 * @param {boolean} useStudentView - Whether to enable student view mode (true) or admin view mode (false).
 * @returns {Promise<UserResource>} - A promise that resolves to the updated user resource.
 * @throws {HttpError} - Throws HttpError if the request fails or user is not an admin.
 */
export async function toggleStudentView(useStudentView: boolean): Promise<UserResource> {
  const apiUrl = `/api/user-management-system/v1/user/student-view`
  const httpClient = new HttpClient(globalConfig.baseUrl, globalConfig.sessionConfig.token)
  return httpClient.patch<UserResource>(apiUrl, { use_student_view: useStudentView })
}