import { html, nothing, PropertyValues } from 'lit'
import { ifDefined } from 'lit/directives/if-defined.js'
import { customElement, property, state } from 'lit/decorators.js'
import { Ref, createRef, ref } from 'lit/directives/ref.js'
import { ElementProps } from '@/types/typeUtils'
import { classMap } from 'lit/directives/class-map.js'
import { PktInputElement } from '@/base-elements/input-element'
import { PktSlotController } from '@/controllers/pkt-slot-controller'

import '@/components/input-wrapper'
import '@/components/icon'

type Props = ElementProps<
  PktTextinput,
  | 'value'
  | 'type'
  | 'size'
  | 'autocomplete'
  | 'iconNameRight'
  | 'prefix'
  | 'suffix'
  | 'omitSearchIcon'
>

@customElement('pkt-textinput')
export class PktTextinput extends PktInputElement<Props> {
  private inputRef: Ref<HTMLTextAreaElement> = createRef()
  private helptextSlot: Ref<HTMLElement> = createRef()

  @property({ type: String, reflect: true }) value: string = ''
  @property({ type: String }) type: string = 'text'
  @property({ type: Number }) size: number | null = null
  @property({ type: String }) autocomplete: string | null = null
  @property({ type: String }) iconNameRight: string | null = null
  @property({ type: String }) prefix: string | null = null
  @property({ type: String }) suffix: string | null = null
  @property({ type: Boolean }) omitSearchIcon: boolean = false

  @state() counterCurrent = 0

  constructor() {
    super()
    this.slotController = new PktSlotController(this, this.helptextSlot)
  }

  attributeChangedCallback(name: string, _old: string | null, value: string | null): void {
    if (name === 'value' && this.value !== _old) {
      this.counterCurrent = value ? value.length : 0
      this.valueChanged(value, _old)
    }
    super.attributeChangedCallback(name, _old, value)
  }

  updated(changedProperties: PropertyValues) {
    super.updated(changedProperties)
    if (changedProperties.has('value')) {
      this.counterCurrent = this.value?.length || 0
      this.valueChanged(this.value, changedProperties.get('value'))
    }
    if (changedProperties.has('id')) {
      !this.name && this.id && (this.name = this.id)
    }
  }

  render() {
    const shouldShowSearchIcon =
      this.type === 'search' && !this.iconNameRight && !this.omitSearchIcon
    const inputClasses = classMap({
      'pkt-input': true,
      'pkt-input--fullwidth': this.fullwidth,
      'pkt-input--counter-error':
        this.counter &&
        this.counterMaxLength &&
        this.value.length &&
        this.value.length > this.counterMaxLength,
    })
    const labelledBy = this.ariaLabelledby || `${this.id}-input-label`

    return html`
      <pkt-input-wrapper
        label="${this.label}"
        ?counter=${this.counter}
        ?disabled=${this.disabled}
        ?hasError=${this.hasError}
        ?hasFieldset=${this.hasFieldset}
        ?inline=${this.inline}
        ?optionalTag=${this.optionalTag}
        ?required=${this.required}
        ?requiredTag=${this.requiredTag}
        ?useWrapper=${this.useWrapper}
        .ariaDescribedBy=${this.ariaDescribedBy}
        .counterCurrent=${this.counterCurrent}
        .counterMaxLength=${this.counterMaxLength}
        .errorMessage=${this.errorMessage}
        .forId="${this.id + '-input'}"
        .helptext=${this.helptext}
        .helptextDropdown=${this.helptextDropdown}
        .helptextDropdownButton=${this.helptextDropdownButton}
        .optionalText=${this.optionalText}
        .requiredText=${this.requiredText}
        .tagText=${this.tagText}
        class="pkt-textinput"
      >
        <div class="pkt-contents" ${ref(this.helptextSlot)} name="helptext" slot="helptext"></div>
        <div class="pkt-input__container">
          ${this.prefix ? html`<div class="pkt-input-prefix">${this.prefix}</div>` : nothing}
          <input
            ${ref(this.inputRef)}
            class=${inputClasses}
            type=${this.type}
            name=${(this.name || this.id) + '-input'}
            id=${this.id + '-input'}
            placeholder=${ifDefined(this.placeholder)}
            aria-labelledby=${labelledBy}
            autocomplete=${this.autocomplete || 'off'}
            minlength=${ifDefined(this.minlength || undefined)}
            maxlength=${ifDefined(this.maxlength || undefined)}
            min=${ifDefined(this.min || undefined)}
            max=${ifDefined(this.max || undefined)}
            step=${ifDefined(this.step || undefined)}
            ?readonly=${this.readonly}
            size=${this.size || nothing}
            .value=${this.value}
            ?disabled=${this.disabled}
            aria-invalid=${this.hasError}
            aria-errormessage=${`${this.id}-error`}
            @input=${(e: InputEvent) => {
              this.value = (e.target as HTMLInputElement).value
              this.onInput()
              e.stopImmediatePropagation()
            }}
            @change=${(e: Event) => {
              e.stopImmediatePropagation()
            }}
            @focus=${(e: FocusEvent) => {
              this.onFocus()
              e.stopImmediatePropagation()
            }}
            @blur=${(e: FocusEvent) => {
              this.value = (e.target as HTMLInputElement).value
              this.onBlur()
              e.stopImmediatePropagation()
            }}
            @keydown=${(e: KeyboardEvent) => {
              if (e.key === 'Enter') {
                const form = this.internals.form as HTMLFormElement
                if (form) {
                  form.requestSubmit()
                } else {
                  this.inputRef.value?.blur()
                }
              }
            }}
          />
          ${this.suffix
            ? html`<div class="pkt-input-suffix">
                ${this.suffix}
                ${this.iconNameRight
                  ? html`<pkt-icon
                      class="pkt-input-suffix-icon"
                      name=${this.iconNameRight}
                    ></pkt-icon>`
                  : nothing}
                ${shouldShowSearchIcon
                  ? html`<pkt-icon
                      class="pkt-input-suffix-icon"
                      name="magnifying-glass-big"
                    ></pkt-icon>`
                  : nothing}
              </div>`
            : nothing}
          ${!this.suffix && this.iconNameRight
            ? html`<pkt-icon class="pkt-input-icon" name=${this.iconNameRight}></pkt-icon>`
            : nothing}
          ${!this.suffix && shouldShowSearchIcon
            ? html`<pkt-icon class="pkt-input-icon" name="magnifying-glass-big"></pkt-icon>`
            : nothing}
        </div>
      </pkt-input-wrapper>
    `
  }
}
