import { type IFile } from '@api-client/core/models/store/File.js'
import { Model } from '../core/Model.js'
import { exponentialBackoffDelay, type RetryOptions, shouldRetryApiError, retry } from './retry_logic.js'
import { fromError } from '../exceptions/builder.js'
import { LiveData } from '../reactive/LiveData.js'
import type SdkService from '../services/SdkService.js'

export enum ModelState {
  /**
   * Not doing anything.
   */
  idle,
  /**
   * Currently querying for file data.
   */
  reading,
  /**
   * Data was received and the result yielded no results or less than the limit.
   */
  ended,
}

export default class FileModel extends Model<LiveData<IFile>> {
  /**
   * The current state of the model.
   */
  state: ModelState = ModelState.idle

  /**
   * A reference to the SDK service used to perform API calls.
   */
  sdk: SdkService

  /**
   * The current Organization ID.
   */
  oid: string

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

  async read(key: string): Promise<LiveData<IFile>> {
    this.debounce(this.#read.bind(this, key), key)
    await this.taskComplete
    return this.value as LiveData<IFile>
  }

  async #read(key: string): Promise<void> {
    if (this.state !== ModelState.idle) {
      return
    }
    this.state = ModelState.reading
    const retryOptions: RetryOptions = {
      delayMs: exponentialBackoffDelay,
      shouldRetry: shouldRetryApiError,
      retries: this.retryCount,
    }
    const operation = async (): Promise<IFile> => {
      return this.sdk.file.read(this.oid, key)
    }
    try {
      const result = await retry(operation, retryOptions)
      this.raw = new LiveData(result)
    } catch (e) {
      const err = fromError(e as Error)
      this.notifyError(err)
      throw err
    } finally {
      this.state = ModelState.idle
    }
    this.dispatchEvent(new Event('querycomplete'))
  }
}
