import { classMap } from 'lit/directives/class-map.js'
import { customElement, property, state } from 'lit/decorators.js'
import { html, PropertyValues } from 'lit'
import { PktElement } from '@/base-elements/element'
import { PktSlotController } from '@/controllers/pkt-slot-controller'
import { ref } from 'lit/directives/ref.js'
import { Ref, createRef } from 'lit/directives/ref.js'
import { TPktSize } from '@/types/size'
import specs from 'componentSpecs/tag.json'

import '@/components/icon'
import { IAriaAttributes } from '@/types/aria'
import { PktIconName } from '@oslokommune/punkt-assets/dist/icons/icon'
import { ifDefined } from 'lit/directives/if-defined.js'

export type TTagSkin =
  | 'blue'
  | 'blue-dark'
  | 'blue-light'
  | 'green'
  | 'red'
  | 'yellow'
  | 'beige'
  | 'gray'
  | 'grey'
export type TTagType = 'button' | 'reset' | 'submit'

export interface IPktTag {
  closeTag?: boolean
  size?: TPktSize
  skin?: TTagSkin
  textStyle?: string | null
  iconName?: PktIconName
  type?: TTagType
  ariaLabel?: IAriaAttributes['aria-label'] | null
}

@customElement('pkt-tag')
export class PktTag extends PktElement<IPktTag> implements IPktTag {
  slotController: PktSlotController
  defaultSlot: Ref<HTMLElement> = createRef()

  constructor() {
    super()
    this.slotController = new PktSlotController(this, this.defaultSlot)
    this._isClosed = false
  }

  /**
   * Element attributes
   */
  @property({ type: Boolean, reflect: true }) closeTag: boolean = specs.props.closeTag.default
  @property({ type: String, reflect: true }) size: TPktSize = specs.props.size.default as TPktSize
  @property({ type: String, reflect: true }) skin: TTagSkin = specs.props.skin.default as TTagSkin
  @property({ type: String, reflect: true }) textStyle: string | null = null
  @property({ type: String, reflect: true }) iconName: string | undefined = undefined
  @property({ type: String }) type: TTagType = specs.props.type.default as TTagType
  @property({ type: String }) ariaLabel: string | null = null

  /**
   * Element state
   */
  @state() _isClosed: boolean = false
  @state() _ariaDescription: string | null = null

  /**
   * Lifecycle
   */

  protected firstUpdated(_changedProperties: PropertyValues): void {
    super.firstUpdated(_changedProperties)

    if (this.closeTag && !this.ariaLabel) {
      const label = this.defaultSlot.value?.textContent?.trim()
      if (label) {
        this._ariaDescription = `Klikk for å fjerne ${label}`
      }
    }
  }

  /**
   * Element functions
   */
  private close = (event: MouseEvent) => {
    this._isClosed = true
    this.dispatchEvent(
      new CustomEvent('close', { detail: { origin: event }, bubbles: true, composed: true }),
    )
    // Historical support of old Vue implementations…
    this.dispatchEvent(
      new CustomEvent('on-close', { detail: { origin: event }, bubbles: true, composed: true }),
    )
  }

  render() {
    const classes = {
      'pkt-tag': true,
      [`pkt-tag--${this.size}`]: !!this.size,
      [`pkt-tag--${this.skin}`]: !!this.skin,
      [`pkt-tag--${this.textStyle}`]: !!this.textStyle,
    }

    const btnClasses = {
      'pkt-tag': true,
      'pkt-btn': true,
      'pkt-btn--tertiary': true,
      [`pkt-tag--${this.textStyle}`]: !!this.textStyle,
      [`pkt-tag--${this.size}`]: !!this.size,
      [`pkt-tag--${this.skin}`]: !!this.skin,
      'pkt-btn--icons-right-and-left': this.closeTag && !!this.iconName,
      'pkt-hide': this._isClosed,
    }

    if (this.closeTag) {
      return html`
        <button
          class=${classMap(btnClasses)}
          type=${this.type}
          @click=${this.close}
          aria-label=${ifDefined(this.ariaLabel || undefined)}
          aria-description=${ifDefined(this._ariaDescription || undefined)}
        >
          ${this.iconName &&
          html`<pkt-icon class="pkt-tag__icon" name=${this.iconName}></pkt-icon>`}
          <span ${ref(this.defaultSlot)}></span>
          <pkt-icon class="pkt-tag__close-btn" name="close"></pkt-icon>
        </button>
      `
    } else {
      return html`
        <span class=${classMap(classes)}>
          ${this.iconName &&
          html`<pkt-icon class="pkt-tag__icon" name=${this.iconName}></pkt-icon>`}
          <span ${ref(this.defaultSlot)}></span>
        </span>
      `
    }
  }
}
