import _ from 'lodash'
import { observable, makeObservable } from 'mobx'

interface DefaultAppState {
  isPaused: boolean
  isRunning: boolean
  nextCommandName: string | null | undefined
  pinnedSnapshotId: number | string | null
  studioActive: boolean
  studioSingleTestActive: boolean
  hasBeenPaused: boolean
}

// these are used for the `reset` method
// so only a subset of the initial values are declared here
const defaults: DefaultAppState = {
  isPaused: false,
  isRunning: false,
  nextCommandName: null,
  pinnedSnapshotId: null,
  studioActive: false,
  studioSingleTestActive: false,
  hasBeenPaused: false,
}

class AppState {
  autoScrollingUserPref = true
  autoScrollingEnabled = true
  isSpecsListOpen = false
  isPaused = defaults.isPaused
  isRunning = defaults.isRunning
  nextCommandName = defaults.nextCommandName
  pinnedSnapshotId = defaults.pinnedSnapshotId
  studioActive = defaults.studioActive
  studioSingleTestActive = defaults.studioSingleTestActive
  showFetchRequests = true
  isStopped = false
  hasBeenPaused = defaults.hasBeenPaused
  _resetAutoScrollingEnabledTo = true
  codeEditorLineWrap = false;
  [key: string]: any

  constructor () {
    makeObservable(this, {
      autoScrollingUserPref: observable,
      autoScrollingEnabled: observable,
      isSpecsListOpen: observable,
      isPaused: observable,
      isRunning: observable,
      nextCommandName: observable,
      pinnedSnapshotId: observable,
      studioActive: observable,
      studioSingleTestActive: observable,
      showFetchRequests: observable,
      hasBeenPaused: observable,
      codeEditorLineWrap: observable,
    })
  }

  startRunning () {
    this.isRunning = true
    this.isStopped = false
  }

  pause (nextCommandName?: string) {
    this.isPaused = true
    this.nextCommandName = nextCommandName
    this.hasBeenPaused = true
  }

  resume () {
    this.isPaused = false
    this.nextCommandName = null
  }

  stop () {
    this.isStopped = true
  }

  end () {
    this.isRunning = false
    this._resetAutoScrolling()
  }

  temporarilySetAutoScrolling (isEnabled?: boolean | null) {
    if (isEnabled != null) {
      this.autoScrollingEnabled = isEnabled
    }
  }

  toggleAutoScrolling () {
    this.setAutoScrolling(!this.autoScrollingEnabled)
  }

  /**
   * Toggles the auto-scrolling user preference to true|false. This method should only be called from the
   * preferences menu itself.
   */
  toggleAutoScrollingUserPref () {
    this.setAutoScrollingUserPref(!this.autoScrollingUserPref)
  }

  toggleSpecList () {
    this.isSpecsListOpen = !this.isSpecsListOpen
  }

  setSpecsList (status: boolean) {
    this.isSpecsListOpen = status
  }

  setAutoScrolling (isEnabled?: boolean | null) {
    if (isEnabled != null) {
      this._resetAutoScrollingEnabledTo = isEnabled
      this.autoScrollingEnabled = isEnabled
    }
  }

  /**
   * Sets the auto scroll user preference to true|false.
   * When this preference is set, it overrides any temporary auto scrolling behaviors that may be in effect.
   * @param {boolean | null | undefined} isEnabled - whether or not auto scroll should be enabled or disabled.
   * If not a boolean, this method is a no-op.
   */
  setAutoScrollingUserPref (isEnabled?: boolean | null) {
    if (isEnabled != null) {
      this.autoScrollingUserPref = isEnabled
      this.setAutoScrolling(isEnabled)
    }
  }

  setStudioActive (studioActive: boolean) {
    this.studioActive = studioActive
  }

  setStudioSingleTestActive (studioSingleTestActive: boolean) {
    this.studioSingleTestActive = studioSingleTestActive
  }

  toggleShowFetchRequests () {
    this.showFetchRequests = !this.showFetchRequests
  }

  toggleCodeEditorLineWrap () {
    this.codeEditorLineWrap = !this.codeEditorLineWrap
  }

  setCodeEditorLineWrap (codeEditorLineWrap: boolean) {
    this.codeEditorLineWrap = codeEditorLineWrap
  }

  setShowFetchRequests (showFetchRequests: boolean) {
    this.showFetchRequests = showFetchRequests
  }

  reset () {
    _.each(defaults, (value: any, key: string) => {
      this[key] = value
    })

    this._resetAutoScrolling()
  }

  _resetAutoScrolling () {
    this.autoScrollingEnabled = this._resetAutoScrollingEnabledTo
  }
}

export { AppState }

export default new AppState()
