import { type IUser } from '@api-client/core/models/store/User.js'
import { Model } from '../core/Model.js'
import { exponentialBackoffDelay, type RetryOptions, shouldRetryApiError, retry } from './retry_logic.js'
import type SdkService from '../services/SdkService.js'

export default class UserModel extends Model<IUser> {
  /**
   * The user ID this model is associated with.
   * Note, this value must be set before calling `fetch()`.
   */
  uid?: string
  /**
   * The organization ID this model is associated with.
   */
  oid: string
  /**
   * A reference to the SDK service used to perform API calls.
   */
  sdk: SdkService
  /**
   * Whether the model is currently loading data.
   */
  loading = false

  constructor(sdk: SdkService, oid: string) {
    super()
    this.sdk = sdk
    this.oid = oid
  }

  async fetch(): Promise<IUser> {
    const { uid, oid } = this
    if (!uid) {
      throw new Error('User ID (uid) is not set. Cannot fetch user data.')
    }
    this.loading = true
    const operation = async (): Promise<IUser> => {
      return this.sdk.organizations.users.read(oid, uid)
    }
    const retryOptions: RetryOptions = {
      retries: this.retryCount,
      delayMs: exponentialBackoffDelay,
      shouldRetry: shouldRetryApiError as (error: Error) => boolean,
    }
    try {
      this.raw = await retry(operation, retryOptions)
    } finally {
      this.loading = false
    }
    return this.raw
  }

  isActive(): boolean {
    const { raw } = this
    if (!raw) {
      throw new Error('User data is not loaded. Cannot determine if user is active.')
    }
    return raw.status === 'active'
  }

  async deactivate(): Promise<void> {
    const { uid, oid } = this
    if (!uid) {
      throw new Error('User ID (uid) is not set. Cannot deactivate user.')
    }
    this.loading = true
    const operation = async (): Promise<IUser> => {
      return this.sdk.organizations.users.deactivate(oid, uid)
    }
    const retryOptions: RetryOptions = {
      retries: this.retryCount,
      delayMs: exponentialBackoffDelay,
      shouldRetry: shouldRetryApiError as (error: Error) => boolean,
    }
    try {
      this.raw = await retry(operation, retryOptions)
    } finally {
      this.loading = false
    }
  }

  async activate(): Promise<void> {
    const { uid, oid } = this
    if (!uid) {
      throw new Error('User ID (uid) is not set. Cannot activate user.')
    }
    this.loading = true
    const operation = async (): Promise<IUser> => {
      return this.sdk.organizations.users.activate(oid, uid)
    }
    const retryOptions: RetryOptions = {
      retries: this.retryCount,
      delayMs: exponentialBackoffDelay,
      shouldRetry: shouldRetryApiError as (error: Error) => boolean,
    }
    try {
      this.raw = await retry(operation, retryOptions)
    } finally {
      this.loading = false
    }
  }
}
