import { PktElementWithSlot } from '@/base-elements/element-with-slot'
import { classMap } from 'lit/directives/class-map.js'
import { customElement, property, state } from 'lit/decorators.js'
import { html, nothing } from 'lit'
import { slotContent } from '@/directives/slot-content'
import { TPktSize } from '@/types/size'
import '@/components/icon'

// Allow global override of animation assets path
window.pktAnimationPath =
  window.pktAnimationPath || 'https://punkt-cdn.oslo.kommune.no/latest/animations/'

export type TPktLoaderVariant = 'blue' | 'rainbow' | 'shapes'

export interface IPktLoader {
  /**
   * The `delay` prop controls how much time the loading should be given before the loader is displayed.
   * This is handy for situations where the load time might be so short that loader is not necessary.
   * Delay time is in milliseconds.
   */
  delay?: number
  /**
   * The `inline` prop decides whether the loader should be displayed inline or not.
   */
  inline?: boolean
  /**
   * The boolean 'isLoading' decides whether the loader or the children will be displayed.
   * If set to false, the children will be displayed.
   */
  isLoading?: boolean
  /**
   * The message to display when the loader is loading.
   */
  message?: string | null
  /**
   * The size of the loader. Default is "medium".
   */
  size?: TPktSize
  /**
   * The variant of the loader. Default is "shapes" which is the OSLO wave loader.
   * Other variants are "blue" and "rainbow" which are spinner variants.
   */
  variant?: TPktLoaderVariant
  /**
   * Override path to loading animations.
   */
  loadingAnimationPath?: string
}

export class PktLoader extends PktElementWithSlot implements IPktLoader {
  @property({ type: Number }) delay: number = 0
  @property({ type: Boolean }) inline: boolean = false
  @property({ type: Boolean }) isLoading: boolean = true
  @property({ type: String }) message: string | null = null
  @property({ type: String }) size: TPktSize = 'medium'
  @property({ type: String }) variant: TPktLoaderVariant = 'shapes'
  @property({ type: String }) loadingAnimationPath: string | undefined = window.pktAnimationPath

  @state() private _shouldDisplayLoader: boolean = false

  connectedCallback() {
    super.connectedCallback()
    this._shouldDisplayLoader = this.delay === 0

    if (this.delay > 0) {
      this.setupLoader()
    }
  }

  updated(changedProperties: Map<string, unknown>) {
    if (changedProperties.has('delay')) {
      this.setupLoader()
    }
  }

  render() {
    const classes = classMap({
      'pkt-loader': true,
      [`pkt-loader--${this.inline ? 'inline' : 'box'}`]: true,
      [`pkt-loader--${this.size}`]: true,
    })

    const slotClasses = classMap({
      'pkt-contents': true,
      'pkt-hide': this.isLoading,
    })

    return html`<div
      role="status"
      aria-live="polite"
      aria-busy=${this.isLoading ? 'true' : 'false'}
      class=${classes}
    >
      ${this.isLoading && this._shouldDisplayLoader
        ? html`<div class="pkt-loader__spinner">
            <pkt-icon
              name=${this.getVariant(this.variant)}
              path=${this.loadingAnimationPath}
              class="pkt-loader__svg pkt-loader__${this.variant}"
            ></pkt-icon>
            ${this.message && html`<p>${this.message}</p>`}
          </div>`
        : nothing}
      <div class=${slotClasses}>${slotContent(this)}</div>
    </div>`
  }

  private getVariant(variant: TPktLoaderVariant): string {
    switch (variant) {
      case 'blue':
        return 'spinner-blue'
      case 'rainbow':
        return 'spinner'
      default:
        return 'loader'
    }
  }

  private setupLoader() {
    if (this.delay > 0) {
      this._shouldDisplayLoader = false
      setTimeout(() => {
        this._shouldDisplayLoader = true
        this.requestUpdate()
      }, this.delay)
    }
  }
}

export default PktLoader

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