import { PktElement } from '@/base-elements/element'
import { PktSlotController } from '@/controllers/pkt-slot-controller'
import { PktIconName } from '@oslokommune/punkt-assets/dist/icons/icon'
import { html, nothing, PropertyValues } from 'lit'
import { property, customElement } from 'lit/decorators.js'
import { classMap } from 'lit/directives/class-map.js'
import { ifDefined } from 'lit/directives/if-defined.js'
import { createRef, Ref, ref } from 'lit/directives/ref.js'

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

type Booleanish = boolean | 'true' | 'false'
export type TPktButtonMode = 'light' | 'dark'
export type TPktButtonSize = 'small' | 'medium' | 'large'
export type TPktButtonColor =
  | 'blue'
  | 'blue-outline'
  | 'green'
  | 'green-outline'
  | 'green-dark'
  | 'green-dark-outline'
  | 'beige-light'
  | 'beige-dark-outline'
  | 'yellow'
  | 'yellow-outline'
  | 'red'
  | 'red-outline'
export type TPktButtonSkin = 'primary' | 'secondary' | 'tertiary'
export type TPktButtonVariant =
  | 'label-only'
  | 'icon-left'
  | 'icon-right'
  | 'icon-only'
  | 'icons-right-and-left'
export type TPktButtonState = 'normal' | 'focus' | 'hover' | 'active'
export type TPktButtonType = 'button' | 'submit' | 'reset'

export interface IPktButton {
  iconName?: PktIconName
  secondIconName?: PktIconName
  mode?: TPktButtonMode
  size?: TPktButtonSize
  color?: TPktButtonColor
  skin?: TPktButtonSkin
  variant?: TPktButtonVariant
  state?: TPktButtonState
  type?: TPktButtonType
  isLoading?: Booleanish
  disabled?: Booleanish
  loadingAnimationPath?: string
}
@customElement('pkt-button')
export class PktButton extends PktElement<IPktButton> implements IPktButton {
  slotController: PktSlotController
  defaultSlot: Ref<HTMLElement> = createRef()

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

  // Properties
  @property({ type: String }) iconName: string = 'user'
  @property({ type: String }) secondIconName: string = 'user'
  @property({ type: String }) mode?: TPktButtonMode = 'light'
  @property({ type: String }) size: TPktButtonSize = 'medium'
  @property({ type: String }) color?: TPktButtonColor
  @property({ type: String }) skin: TPktButtonSkin = 'primary'
  @property({ type: String }) variant: TPktButtonVariant = 'label-only'
  @property({ type: String, reflect: true }) state?: TPktButtonState = 'normal'
  @property({ type: String, reflect: true }) type: TPktButtonType = 'button'
  @property({ type: String }) form: string | undefined = undefined
  @property({ type: Boolean, reflect: true }) isLoading: Booleanish = false
  @property({ type: Boolean, reflect: true }) disabled: Booleanish = false
  @property({ type: String }) loadingAnimationPath: string | undefined = window.pktAnimationPath

  // Lifecycle

  connectedCallback(): void {
    super.connectedCallback()
    this.addEventListener(
      'click',
      (e) => {
        if (this.disabled || this.hasAttribute('disabled') || this.isLoading) {
          e.preventDefault()
          e.stopImmediatePropagation()
        }
      },
      true,
    )

    this.addEventListener(
      'keydown',
      (e) => {
        if (!(this.disabled || this.hasAttribute('disabled') || this.isLoading)) return
        if (e.key === 'Enter' || e.key === ' ') {
          e.preventDefault()
          e.stopImmediatePropagation()
        }
      },
      true,
    )
  }

  attributeChangedCallback(name: string, _old: string | null, value: string | null): void {
    super.attributeChangedCallback(name, _old, value)
    // Convert strings to booleans
    if (name === 'disabled' && value === 'false') {
      this.disabled = false
    }
    if ((name === 'isloading' || name === 'isLoading') && value === 'false') {
      this.isLoading = false
    }
  }

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

    if (this.disabled === 'false') {
      this.disabled = false
    }
    if (this.isLoading === 'false') {
      this.isLoading = false
    }
  }

  // Render

  render() {
    const formId = this.form ?? this.getAttribute('form') ?? undefined

    const classes = {
      'pkt-btn': true,
      [`pkt-btn--${this.size}`]: !!this.size,
      [`pkt-btn--${this.skin}`]: !!this.skin,
      [`pkt-btn--${this.variant}`]: !!this.variant,
      [`pkt-btn--${this.color}`]: !!this.color,
      [`pkt-btn--${this.state}`]: !!this.state,
      'pkt-btn--disabled': !!this.disabled,
      'pkt-btn--isLoading': !!this.isLoading,
    }

    return html`
      <button
        class=${classMap(classes)}
        type=${this.type}
        ?disabled=${!!this.disabled}
        aria-busy=${ifDefined(this.isLoading ? 'true' : undefined)}
        aria-disabled=${ifDefined(this.disabled || this.isLoading ? 'true' : undefined)}
        form=${ifDefined(formId)}
      >
        ${this.isLoading
          ? html`<pkt-icon
              class="pkt-btn__icon pkt-btn__spinner"
              name="spinner-blue"
              path=${ifDefined(this.loadingAnimationPath)}
            ></pkt-icon>`
          : nothing}
        ${this.variant !== 'label-only'
          ? html`<pkt-icon class="pkt-btn__icon pkt-icon" name=${this.iconName}></pkt-icon>`
          : nothing}
        <span class="pkt-btn__text" ${ref(this.defaultSlot)}></span>
        ${this.variant === 'icons-right-and-left'
          ? html`<pkt-icon class="pkt-btn__icon" name=${this.secondIconName}></pkt-icon>`
          : nothing}
      </button>
    `
  }
}

export default PktButton
