import { PktElement } from '@/base-elements/element'
import { html, nothing } from 'lit'
import { customElement, property } from 'lit/decorators.js'
import { classMap } from 'lit/directives/class-map.js'
import { ifDefined } from 'lit/directives/if-defined.js'
import { FocusModalityController } from '@/controllers/focus-modality-controller'

import '@/components/icon'

import type {
  IPktSearchInput,
  IPktSearchInputSuggestion,
  TPktSearchInputAppearance,
  TPktSearchInputMethod,
} from 'shared-types/searchinput'

export type {
  IPktSearchInput,
  IPktSearchInputSuggestion,
  TPktSearchInputAppearance,
  TPktSearchInputMethod,
} from 'shared-types/searchinput'

export class PktSearchInput extends PktElement<IPktSearchInput> implements IPktSearchInput {
  @property({ type: String }) appearance: TPktSearchInputAppearance = 'local'
  @property({ type: Boolean, reflect: true }) disabled: boolean = false
  @property({ type: Boolean, reflect: true }) fullwidth: boolean = false
  @property({ type: String, reflect: true }) id: string = ''
  @property({ type: String }) label: string | undefined
  @property({ type: String }) name: string | undefined
  @property({ type: String }) placeholder: string = 'Søk…'
  @property({ type: String }) value: string = ''
  @property({ type: Array }) suggestions: IPktSearchInputSuggestion[] | undefined
  @property({ type: String }) action: string | undefined
  @property({ type: String }) method: TPktSearchInputMethod | undefined

  focusModality = new FocusModalityController(this, '.pkt-searchinput')

  private get suggestionsId() {
    return `${this.id}-suggestions`
  }

  private dispatchSearch(): void {
    this.dispatchEvent(
      new CustomEvent('pkt-search', {
        detail: { value: this.value },
        bubbles: true,
        composed: true,
      }),
    )
  }

  private onInput(event: InputEvent): void {
    const target = event.target as HTMLInputElement
    this.value = target.value
  }

  private onInputKeydown(event: KeyboardEvent): void {
    if (event.key !== 'Enter') return
    event.preventDefault()
    this.dispatchSearch()
  }

  private onSearchClick(event: Event): void {
    event.preventDefault()
    this.dispatchSearch()
  }

  private onSuggestionClick(
    event: Event,
    suggestion: IPktSearchInputSuggestion,
    index: number,
  ): void {
    const customEvent = new CustomEvent('pkt-suggestion-click', {
      detail: {
        index,
        suggestion,
      },
      bubbles: true,
      composed: true,
      cancelable: true,
    })
    const allowed = this.dispatchEvent(customEvent)
    if (!allowed) {
      event.preventDefault()
    }
  }

  private renderSuggestion(suggestion: IPktSearchInputSuggestion, index: number) {
    const suggestionContent = html`
      ${suggestion.title
        ? html`<h3 class="pkt-searchinput__suggestion-title">${suggestion.title}</h3>`
        : nothing}
      ${suggestion.text
        ? html`<p class="pkt-searchinput__suggestion-text">${suggestion.text}</p>`
        : nothing}
    `

    if (suggestion.href) {
      return html`<a
        href=${suggestion.href}
        class="pkt-searchinput__suggestion"
        @click=${(event: Event) => this.onSuggestionClick(event, suggestion, index)}
      >
        ${suggestionContent}
      </a>`
    }

    if (suggestion.nonInteractive) {
      return html`<div class="pkt-searchinput__suggestion">${suggestionContent}</div>`
    }

    return html`<button
      type="button"
      class="pkt-searchinput__suggestion"
      @click=${(event: Event) => this.onSuggestionClick(event, suggestion, index)}
    >
      ${suggestionContent}
    </button>`
  }

  render() {
    const wrapperClasses = classMap({
      'pkt-searchinput': true,
      [`pkt-searchinput--${this.appearance}`]: true,
      'pkt-searchinput--fullwidth': this.fullwidth,
    })
    const buttonClasses = classMap({
      'pkt-searchinput__button': true,
      'pkt-input-icon': this.appearance === 'local',
      'pkt-btn': true,
      'pkt-btn--medium': true,
      'pkt-btn--icon-only': true,
      'pkt-btn--tertiary': this.appearance === 'local',
      'pkt-btn--primary': this.appearance === 'global' || this.appearance === 'local-with-button',
      'pkt-btn--yellow': this.appearance === 'global',
    })
    const inputClasses = classMap({
      'pkt-input': true,
      'pkt-input--fullwidth': this.fullwidth,
    })
    const fieldClass =
      this.appearance === 'local' ? 'pkt-input__container' : 'pkt-searchinput__field'

    const body = html`
      ${this.label
        ? html`<label for=${ifDefined(this.id || undefined)} class="pkt-inputwrapper__label"
            >${this.label}</label
          >`
        : nothing}
      <div class=${fieldClass}>
        <input
          class=${inputClasses}
          type="search"
          name=${this.name || this.id}
          id=${this.id}
          placeholder=${this.placeholder || 'Søk…'}
          .value=${this.value}
          ?disabled=${this.disabled}
          autocomplete="off"
          aria-autocomplete="list"
          aria-controls=${this.suggestionsId}
          @input=${this.onInput}
          @keydown=${this.onInputKeydown}
        />
        <button
          type="submit"
          class=${buttonClasses}
          ?disabled=${this.disabled}
          @click=${this.onSearchClick}
        >
          <pkt-icon class="pkt-btn__icon" name="magnifying-glass-big" />
          <span class="pkt-btn__text">${this.label || this.placeholder || 'Søk…'}</span>
        </button>
      </div>
      ${this.suggestions
        ? html`<ul
            id=${this.suggestionsId}
            class="pkt-searchinput__suggestions"
            aria-live="assertive"
          >
            ${this.suggestions.map(
              (suggestion, index) => html` <li>${this.renderSuggestion(suggestion, index)}</li> `,
            )}
          </ul>`
        : nothing}
    `

    if (this.action) {
      return html`<form
        role="search"
        class=${wrapperClasses}
        action=${this.action}
        method=${ifDefined(this.method)}
        @submit=${(event: Event) => {
          event.preventDefault()
        }}
      >
        ${body}
      </form>`
    }

    return html`<div role="search" class=${wrapperClasses}>${body}</div>`
  }
}

export default PktSearchInput

try {
  customElement('pkt-searchinput')(PktSearchInput)
} catch (e) {
  console.warn('Forsøker å definere <pkt-searchinput>, men den er allerede definert')
}
