import {DataUtil, getUniqueIdWithPrefix, EventHandlerUtil} from '../_utils/index'
// Helpers
import {CookieComponent} from './_CookieComponent'

export interface ToggleOptions {
  saveState: boolean
  targetState?: string
  toggleState?: string
  targetToggleMode?: string
}

const defaultToggleOptions: ToggleOptions = {
  saveState: false,
}

class ToggleComponent {
  element: HTMLElement
  instanceUid: string
  options: ToggleOptions
  state: string = ''
  mode: string = ''
  target: HTMLElement | null = null
  attribute: string = ''

  constructor(_element: HTMLElement, options: ToggleOptions) {
    this.options = Object.assign(defaultToggleOptions, options)
    this.instanceUid = getUniqueIdWithPrefix('toggle')
    this.element = _element

    const elementTargetAttr = this.element.getAttribute('data-kt-toggle-target')
    if (elementTargetAttr) {
      this.target = document.querySelector(elementTargetAttr)
    }
    const elementToggleAttr = this.element.getAttribute('data-kt-toggle-state')
    this.state = elementToggleAttr || ''
    const elementModeAttr = this.element.getAttribute('data-kt-toggle-mode')
    this.mode = elementModeAttr || ''
    this.attribute = 'data-kt-' + this.element.getAttribute('data-kt-toggle-name')

    // Event Handlers
    this._handlers()

    // Update Instance
    // Bind Instance
    DataUtil.set(this.element, 'toggle', this)
  }

  private _handlers = () => {
    this.element.addEventListener('click', (e: Event) => {
      e.preventDefault()

      if (this.mode === '') {
        this._toggle()
        return
      }

      if (this.mode === 'off' && !this._isEnabled()) {
        this._toggle()
      } else if (this.mode === 'on' && this._isEnabled()) {
        this._toggle()
      }
    })
  }

  // Event handlers
  private _toggle = () => {
    // Trigger "after.toggle" event
    EventHandlerUtil.trigger(this.element, 'kt.toggle.change')

    if (this._isEnabled()) {
      this._disable()
    } else {
      this._enable()
    }

    // Trigger "before.toggle" event
    EventHandlerUtil.trigger(this.element, 'kt.toggle.changed')
    return this
  }

  private _enable = () => {
    if (this._isEnabled()) {
      return
    }

    EventHandlerUtil.trigger(this.element, 'kt.toggle.enable')
    this.target?.setAttribute(this.attribute, 'on')
    if (this.state.length > 0) {
      this.element.classList.add(this.state)
    }

    if (this.options.saveState) {
      CookieComponent.set(this.attribute, 'on', {})
    }

    EventHandlerUtil.trigger(this.element, 'kt.toggle.enabled')
    return this
  }

  private _disable = () => {
    if (!this._isEnabled()) {
      return false
    }

    EventHandlerUtil.trigger(this.element, 'kt.toggle.disable')
    this.target?.removeAttribute(this.attribute)

    if (this.state.length > 0) {
      this.element.classList.remove(this.state)
    }

    if (this.options.saveState) {
      CookieComponent.delete(this.attribute)
    }

    EventHandlerUtil.trigger(this.element, 'kt.toggle.disabled')
    return this
  }

  private _isEnabled = () => {
    if (!this.target) {
      return false
    }

    return String(this.target.getAttribute(this.attribute)).toLowerCase() === 'on'
  }

  ///////////////////////
  // ** Public API  ** //
  ///////////////////////

  // Plugin API
  // Plugin API
  public toggle = () => {
    return this._toggle()
  }

  public enable = () => {
    return this._enable()
  }

  public disable = () => {
    return this._disable()
  }

  public isEnabled = () => {
    return this._isEnabled()
  }

  public goElement = () => {
    return this.element
  }

  // Event API
  public on = (name: string, handler: Function) => {
    return EventHandlerUtil.on(this.element, name, handler)
  }

  public one = (name: string, handler: Function) => {
    return EventHandlerUtil.one(this.element, name, handler)
  }

  public off = (name: string, handlerId: string) => {
    return EventHandlerUtil.off(this.element, name, handlerId)
  }

  public trigger = (name: string, event?: Event) => {
    return EventHandlerUtil.trigger(this.element, name, event)
  }

  // Static methods
  public static getInstance = (el: HTMLElement) => {
    const toggleElement = DataUtil.get(el, 'toggle')
    if (toggleElement) {
      return toggleElement
    }

    return null
  }

  public static createInstances = (selector: string) => {
    const elements = document.body.querySelectorAll<HTMLElement>(selector)
    elements.forEach((el) => {
      let toggle = ToggleComponent.getInstance(el)
      if (!toggle) {
        toggle = new ToggleComponent(el, defaultToggleOptions)
      }
    })
  }

  public static reinitialization = () => {
    ToggleComponent.createInstances('[data-kt-toggle]')
  }

  public static bootstrap = () => {
    ToggleComponent.createInstances('[data-kt-toggle]')
  }
}

export {ToggleComponent, defaultToggleOptions}
