import type { FileBreadcrumb } 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'
import { ContextListResult } from '@api-client/core/events/BaseEvents.js'

export enum ModelState {
  /**
   * Not doing anything.
   */
  idle,
  /**
   * Currently querying for breadcrumb data.
   */
  reading,
}

export default class BreadcrumbsModel extends Model<FileBreadcrumb[]> {
  /**
   * The current state of the model.
   */
  state: ModelState = ModelState.idle

  /**
   * The current breadcrumbs
   */
  breadcrumbs: LiveData<FileBreadcrumb[]> = new LiveData<FileBreadcrumb[]>([])

  /**
   * 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
  }

  reset(): void {
    this.state = ModelState.idle
    this.breadcrumbs.set([])
  }

  async scheduleQuery(parent?: string): Promise<void> {
    this.debounce(() => this.#query(parent), parent)
    await this.taskComplete
  }

  async #query(parent?: string): Promise<void> {
    if (this.state !== ModelState.idle) {
      // This should not happen due to debouncing, but just in case
      return
    }
    if (!parent) {
      this.breadcrumbs.set([])
      return
    }
    this.state = ModelState.reading
    const operation = async (): Promise<ContextListResult<FileBreadcrumb>> => {
      return this.sdk.file.breadcrumbs(this.oid, parent)
    }
    const retryOptions: RetryOptions = {
      retries: this.retryCount,
      delayMs: exponentialBackoffDelay,
      shouldRetry: shouldRetryApiError as (error: Error) => boolean,
    }
    try {
      const br = await retry(operation, retryOptions)
      this.breadcrumbs.set(br.items)
    } catch (e) {
      const err = fromError(e as Error)
      this.notifyError(err)
    } finally {
      this.state = ModelState.idle
    }
  }
}
