import { LitElement } from 'lit'
import { property } from 'lit/decorators.js'

export declare class PlaceholderEditableMixinInterface {
  input: HTMLInputElement | HTMLTextAreaElement
  placeholder?: string
  placeholderEditable: boolean
}

export const PlaceholderEditableMixin = <T extends Constructor<LitElement>>(
  superClass: T,
) => {
  class PlaceholderEditableMixinClass extends superClass {
    private _input?: HTMLInputElement | HTMLTextAreaElement
    private _originalPlaceholder?: string

    @property()
    placeholder?: string
    @property({ type: Boolean, attribute: 'placeholder-editable' })
    placeholderEditable = false

    get input() {
      return this._input
    }

    set input(_input) {
      if (!_input) return

      // Push props down...
      if (this.placeholder) {
        _input.placeholder = this.placeholder
      }

      if (this.placeholderEditable) {
        _input.setAttribute('data-editable-placeholder', '')
      }

      // Only run changed if the input element has changed.
      if (!this._input?.isEqualNode(_input)) {
        this._input = _input
        this.onInputElementChanged()
      }
    }

    get value() {
      return this._input?.value
    }

    set value(_val) {
      if (_val !== undefined && this._input) {
        this._input.value = _val
      }
    }

    constructor(...args: any) {
      super()
      this.placeholderEditable = false
    }

    private onInputElementChanged() {
      if (this.placeholderEditable) {
        this._input?.addEventListener('blur', this.handleBlur.bind(this))
        this._input?.addEventListener('focus', this.handleFocus.bind(this))
        this._input?.addEventListener('mouseenter', this.handleFocus.bind(this))
        this._input?.addEventListener('mouseleave', this.handleBlur.bind(this))
      }
    }

    private handleFocus() {
      if (!this.value) {
        this.value = this._originalPlaceholder = this._input?.placeholder || ''
      }
    }

    private handleBlur() {
      if (
        document.activeElement !== this._input &&
        this.value === this._originalPlaceholder
      ) {
        this.value = ''
      }
    }
  }
  return PlaceholderEditableMixinClass as Constructor<PlaceholderEditableMixinInterface> &
    T
}
