import { LitElement, html } from 'lit'
import { customElement, property, state } from 'lit/decorators.js'
import { EventEmitterMixin } from '../EventEmitterMixin'
import getComponentKey from '../util/getComponentKey'
import ifUnmodified from '../dom/ifUnmodified'

const ls = window.localStorage
const collapseTooltip = window.BRIGHTSPOT?.ui.tooltips.collapse
const expandTooltip = window.BRIGHTSPOT?.ui.tooltips.expand

@customElement('btu-widget')
export default class Widget extends EventEmitterMixin(LitElement) {
  private _collapsed = false

  @property({ type: Boolean })
  collapsible = false

  @property({ type: String })
  heading?: string

  @property({ type: String })
  internalname?: string

  @state()
  invalid = false

  @property({ type: String })
  widgetid?: string

  // Sets the initial closed state of the widget.
  // Priority: initialClosed > localStorage > default (false)
  @property({ type: Boolean, attribute: 'initial-closed' })
  initialClosed = false

  @property({ type: Boolean })
  set collapsed(isCollapsed: boolean) {
    this._collapsed = isCollapsed

    const key = getComponentKey(this, 'data-internal-name')
    if (key) {
      if (isCollapsed) {
        ls.setItem(key, '1')
      } else {
        ls.removeItem(key)
      }
    }

    this.requestUpdate()
    this.emit('btu-widget-toggle')
  }

  get collapsed() {
    return this._collapsed
  }

  connectedCallback(): void {
    super.connectedCallback()

    // initialClosed only affects collapsible widgets
    if (this.collapsible && this.initialClosed) {
      this._collapsed = true
    } else if (this.collapsible) {
      const key = getComponentKey(this, 'data-internal-name')
      this._collapsed = !!(key && ls.getItem(key))
    }
  }

  createRenderRoot() {
    return this
  }

  firstUpdated(): void {
    this.emit('btu-widget-ready')

    this.invalid = this.querySelector('.Message.is-error') != null

    // Expand widget if not collapsible or has errors
    if (!this.collapsible || this.invalid) {
      this.collapsed = false
    }

    const widgetTitle = this.querySelector<HTMLElement>('.Widget-title')

    // Ensures that the title is always the first child of the widget.
    const firstChild = this.firstChild
    if (
      firstChild instanceof Element &&
      !firstChild.classList.contains('Widget-title')
    ) {
      if (widgetTitle) {
        this.insertBefore(widgetTitle, firstChild)
      }
    }

    // Hide all children added after render of the widget if it is collapsed
    this.querySelectorAll<HTMLElement>(
      ':scope > :not(.Widget-title, script, select)',
    ).forEach((el) => {
      el.toggleAttribute('hidden', this.collapsed && !this.invalid)
    })
  }

  render() {
    this.classList.add('widget', 'Widget')

    // Add the collapsible class if the widget can be collapsible.
    this.classList.toggle('is-collapsible', this.collapsible)

    this.classList.toggle('is-collapsed', this.collapsed)

    // If there are error messages, expand the widget.
    this.classList.toggle('is-error', this.invalid)

    // Hide all children of the widget if it is collapsed.
    this.querySelectorAll<HTMLElement>(
      ':scope > :not(.Widget-title, script, select)',
    ).forEach((el) => {
      el.toggleAttribute('hidden', this.collapsed)
    })

    if (this.collapsible) {
      return html`<h2
        class="Widget-title"
        @click="${() => (this.collapsed = !this.collapsed)}"
      >
        <div
          class="Widget-expand"
          role="button"
          tabindex="0"
          aria-expanded=${!this.collapsed}
          title=${this.collapsed ? expandTooltip : collapseTooltip}
          @keydown=${ifUnmodified((e: unknown) => {
            if (e instanceof KeyboardEvent) {
              if (e.key === 'Enter' || e.key === ' ') {
                e.preventDefault()
                this.collapsed = !this.collapsed
              }
            }
          })}
        >
          ${this.heading}
          <ul class="Widget-controls" aria-hidden="true">
            <li
              class="Widget-collapse"
              title="${this.collapsed ? expandTooltip : collapseTooltip}"
            ></li>
          </ul>
        </div>
      </h2>`
    } else {
      return html`<h2 class="Widget-title">${this.heading}</h2>`
    }
  }
}

declare global {
  interface HTMLElementTagNameMap {
    'btu-widget': Widget
  }
}
