import { classMap } from 'lit/directives/class-map.js'
import { customElement, property, state } from 'lit/decorators.js'
import { html, nothing, PropertyValues } from 'lit'
import { PktElement } from '@/base-elements/element'
import { PktSlotController } from '@/controllers/pkt-slot-controller'
import { ref, createRef, Ref } from 'lit/directives/ref.js'
import { TAriaLive } from '@/types/aria'
import { updateClassAttribute } from '@/utils/classutils'
import specs from 'componentSpecs/alert.json'

import '@/components/icon'

export type TAlertSkin = 'error' | 'success' | 'warning' | 'info'

export interface IPktAlert {
  skin?: TAlertSkin
  closeAlert?: boolean
  title?: string
  date?: string | null
  ariaLive?: TAriaLive | null
  'aria-live'?: TAriaLive | null
  compact?: boolean
  role?: string
}
@customElement('pkt-alert')
export class PktAlert extends PktElement implements IPktAlert {
  defaultSlot: Ref<HTMLElement> = createRef()

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

  // Properties

  @property({ type: Boolean, reflect: false }) compact = specs.props.compact.default
  @property({ type: String, reflect: true }) title: string = ''
  @property({ type: String, reflect: true }) skin: TAlertSkin = specs.props.skin
    .default as TAlertSkin
  @property({ type: String }) ariaLive: TAriaLive = specs.props.ariaLive.default as TAriaLive
  @property({ type: String, reflect: true }) 'aria-live': TAriaLive | null = null
  @property({ type: Boolean, reflect: true }) closeAlert = specs.props.closeAlert.default
  @property({ type: String, reflect: true }) date: string | null = null
  @property({ type: String, reflect: true }) role: string = 'status'

  @state() _isClosed: boolean = false

  // Lifecycle

  connectedCallback(): void {
    super.connectedCallback()
    this['aria-live'] = (this.getAttribute('aria-live') as TAriaLive) || this.ariaLive
  }

  attributeChangedCallback(name: string, _old: string | null, value: string | null): void {
    if (name === 'ariaLive') {
      this['aria-live'] = value as TAriaLive
    }
    super.attributeChangedCallback(name, _old, value)
  }

  protected updated(_changedProperties: PropertyValues): void {
    super.updated(_changedProperties)
    if (_changedProperties.has('ariaLive')) {
      this['aria-live'] = this.ariaLive
    }
    if (_changedProperties.has('_isClosed')) {
      updateClassAttribute(this, 'pkt-hide', this._isClosed)
    }
  }

  // Render

  render() {
    const classes = {
      'pkt-alert': true,
      'pkt-alert--compact': this.compact,
      [`pkt-alert--${this.skin}`]: this.skin,
      'pkt-hide': this._isClosed,
    }

    const gridClasses = {
      'pkt-alert__grid': true,
      'pkt-alert__noTitle': !this.title,
      'pkt-alert__noDate': !this.date,
    }

    return html`
      <div class=${classMap(classes)} aria-live=${this['aria-live']}>
        <div class=${classMap(gridClasses)}>
          <pkt-icon
            class="pkt-alert__icon"
            aria-hidden="true"
            name=${this.skin === 'info' ? 'alert-information' : `alert-${this.skin}`}
          ></pkt-icon>

          ${this.closeAlert
            ? html`
                <div class="pkt-alert__close">
                  <pkt-button
                    tabindex="0"
                    aria-label="close"
                    size=${this.compact ? 'small' : 'medium'}
                    type="button"
                    skin="tertiary"
                    iconName="close"
                    variant="icon-only"
                    @click=${this.close}
                  >
                  </pkt-button>
                </div>
              `
            : nothing}
          ${this.title ? html`<div class="pkt-alert__title">${this.title}</div>` : nothing}

          <div class="pkt-alert__text" ${ref(this.defaultSlot)}></div>

          ${this.date
            ? html`<div class="pkt-alert__date">Sist oppdatert: ${this.date}</div>`
            : nothing}
        </div>
      </div>
    `
  }

  // Methods

  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 }),
    )
  }
}
