import {Component, Listen, Prop, State, Element, h} from '@stencil/core';
import {AccordionVariants} from '../../utils/utils';

let keys = {
  enter: 'Enter', //13
  tab: 'Tab', //9
  pageUp: 'PageUp', //33
  pageDown: 'PageDown', //34
  arrowUp: 'ArrowUp', // 38
  arrowDown: 'ArrowDown', //40
  home: 'Home', //36
  end: 'End', //35
};

@Component({
  tag: 'hy-accordion-item',
  styleUrl: 'accordion-item.scss',
  shadow: false,
})
export class AccordionItem {
  @Element() el: HTMLElement;
  @Prop() accordiontitle?: string;
  @Prop() variant: AccordionVariants = AccordionVariants.default;
  @Prop() headerstyle: string = 'common';
  @State() ready: boolean = false;

  componentDidLoad() {
    this.ready = true;

    let hyMainDiv = this.el.closest('.hy-main');
    if (hyMainDiv) {
      if (!hyMainDiv.classList.contains('with-sidebar')) {
        this.headerstyle = 'large';
      }
    }
  }

  componentDidRender() {
    if (window.location.hash) {
      this.expandPanelByAnchor(window.location.hash);
    }
  }

  @Listen('hashchange', {target: 'window'})
  onHashChange() {
    if (window.location.hash) {
      this.expandPanelByAnchor(window.location.hash);
    }
  }

  @Listen('keydown')
  handleKeyDown(event: KeyboardEvent) {
    const containerId = this.el.parentElement.id;
    let accordion = document.querySelectorAll(`#${containerId}`)[0];

    const triggers = Array.prototype.slice.call(accordion.querySelectorAll('.hy-accordion__button'));
    let target = event.target as HTMLButtonElement;
    const key = event.code;

    const ctrlModifier = event.ctrlKey && [keys.pageDown, keys.pageUp].includes(key); //key.match(/33|34/);

    if (target.classList.contains('hy-accordion__button')) {
      // Up/ Down arrow and Control + Page Up/ Page Down keyboard operations
      if ([keys.arrowDown, keys.arrowUp].includes(key) || ctrlModifier) {
        const index = triggers.indexOf(target);
        const direction = [keys.arrowDown, keys.pageDown].includes(key) ? 1 : -1;
        const length = triggers.length;
        const newIndex = (index + length + direction) % length;
        triggers[newIndex].focus();

        event.preventDefault();
      } else if ([keys.home, keys.end].includes(key)) {
        switch (key) {
          // Go to first accordion
          case keys.home:
            triggers[0].focus();
            break;
          // Go to last accordion
          case keys.end:
            triggers[triggers.length - 1].focus();
            break;
        }
        event.preventDefault();
      }
    }
  }

  @Listen('click')
  handleClick(event) {
    const containerId = this.el.parentElement.id;

    let target = event.target as HTMLTextAreaElement;
    const targetElement = target.tagName.toLowerCase();
    const possibleTags = [targetElement].some((r) => ['svg', 'span', 'path', 'button', 'a'].indexOf(r) >= 0);

    let accordion = document.querySelectorAll(`#${containerId}`)[0];
    const allowMultiple = accordion.hasAttribute('data-allow-multiple');
    const allowToggle = allowMultiple ? allowMultiple : accordion.hasAttribute('data-allow-toggle');

    if (target && possibleTags) {
      if (targetElement !== 'button') {
        target = target.closest('.hy-accordion__button');
      }

      let targetParent = target.closest('.hy-accordion__item');
      let targetContent = targetParent.querySelectorAll('.hy-accordion__content')[0];
      const isExpanded = target.getAttribute('aria-expanded') == 'true';
      const active = accordion.querySelector('[aria-expanded="true"]');

      if (!allowMultiple && active && active !== target) {
        active.setAttribute('aria-expanded', 'false');
        this.collapseSection(targetContent);
        if (targetParent.classList.contains('hy-accordion__item__is-open')) {
          targetParent.classList.remove('hy-accordion__item__is-open');
        }
        accordion.querySelector(`#${active.getAttribute('aria-controls')}`).setAttribute('aria-hidden', 'true');

        if (!allowToggle) {
          active.removeAttribute('aria-disabled');
        }
      }

      if (!isExpanded) {
        this.expandSection(targetContent);
        target.setAttribute('aria-expanded', 'true');
        targetParent.classList.add('hy-accordion__item__is-open');

        accordion.querySelector(`#${target.getAttribute('aria-controls')}`).setAttribute('aria-hidden', 'false');

        if (!allowToggle) {
          target.setAttribute('aria-disabled', 'true');
        }
      } else if (allowToggle && isExpanded) {
        target.setAttribute('aria-expanded', 'false');
        this.collapseSection(targetContent);
        if (targetParent.classList.contains('hy-accordion__item__is-open')) {
          targetParent.classList.remove('hy-accordion__item__is-open');
        }
        accordion.querySelector(`#${target.getAttribute('aria-controls')}`).setAttribute('aria-hidden', 'true');
      }

      event.preventDefault();
      event.stopImmediatePropagation();
    }
  }

  expandPanelByAnchor(anchor) {
    if (anchor.length > 0) {
      anchor = anchor.substr(1);
      let target = document.querySelectorAll(`[id=${anchor}]`)[0];
      if (target && target.classList.contains('hy-accordion__button')) {
        let targetParent = target.closest('.hy-accordion__item');
        let targetContent = targetParent.querySelectorAll('.hy-accordion__content')[0];

        this.expandSection(targetContent);
        target.setAttribute('aria-expanded', 'true');
        targetParent.classList.add('hy-accordion__item__is-open');

        const containerId = targetParent.parentElement.parentElement.id;
        if (containerId.length > 0) {
          let accordion = document.querySelectorAll(`#${containerId}`)[0];
          accordion.querySelector(`#${target.getAttribute('aria-controls')}`).setAttribute('aria-hidden', 'false');
        }
      }
    }
  }

  collapseSection(element) {
    element.style.height = 0 + 'px';
    element.setAttribute('data-collapsed', 'true');
    setTimeout(() => {
      element.style.display = 'none';
    }, 250);
  }

  expandSection(element) {
    element.style.display = 'block';
    element.style.height = element.scrollHeight + 'px';
    element.setAttribute('data-collapsed', 'false');
  }

  render() {
    const containerId = this.el.parentElement.id;

    if (this.ready && containerId.length > 0) {
      document.querySelectorAll(`#${containerId}`).forEach(function (accordion) {
        if (accordion) {
          accordion.querySelectorAll('.hy-accordion__button').forEach(function (trigger) {
            trigger.addEventListener('focus', function () {
              trigger.classList.add('focus');
            });
            trigger.addEventListener('blur', function () {
              trigger.classList.remove('focus');
            });
          });
        }
      });
    }

    const classAttributes = ['hy-accordion__item', this.variant].join(' ');
    const classInnerWrapper = ['hy-accordion__item--container', this.variant].join(' ');
    const classHeadingAttributes = ['hy-accordion--heading', this.variant].join(' ');
    const classContentAttributes = [
      'hy-accordion__content',
      `hy-accordion__content--${this.variant}`,
      this.variant,
    ].join(' ');
    const classContentInnerWrapper = [
      'hy-accordion__content--inner-wrapper',
      `hy-accordion__content--inner-wrapper--${this.headerstyle}`,
      `hy-accordion__content--inner-wrapper--${this.variant}`,
    ].join(' ');

    const titleAsId = this.accordiontitle.toLowerCase().replace(/\W/g, '-');
    const accordionItemHref = '#' + titleAsId + '--title';

    return (
      <div class={classAttributes}>
        <div class={classInnerWrapper}>
          <div class={classHeadingAttributes}>
            <a href={accordionItemHref} class="hy-accordion__link" tabindex="-1">
              <button
                aria-expanded="false"
                aria-controls={`${titleAsId}--content`}
                class={`hy-accordion__button hy-accordion__button--${this.headerstyle}`}
                id={`${titleAsId}--title`}
              >
                <span class="hy-accordion--heading__icon">
                  <hy-icon icon={'hy-icon-caret-down'} size={20} />
                </span>
                <span>{this.accordiontitle}</span>
              </button>
            </a>
          </div>
          <div
            aria-labelledBy={`${titleAsId}--title`}
            class={classContentAttributes}
            id={`${titleAsId}--content`}
            role="region"
            aria-hidden="true"
            style={{display: 'none'}}
          >
            <div class={classContentInnerWrapper}>
              <slot></slot>
            </div>
          </div>
        </div>
      </div>
    );
  }
}