<template lang="pug">
.w-accordion__item(:class="itemClasses" :aria-expanded="accordionItem._expanded ? 'true' : 'false'")
  .w-accordion__item-title(
    @click="!accordionItem._disabled && toggleItem(accordionItem, $event)"
    @pointerdown="onAccordionTitlePointerDown"
    @focus="$emit('focus', (accordionItem))"
    @keypress.enter="!accordionItem._disabled && toggleItem(accordionItem, $event)"
    :tabindex="!accordionItem._disabled && 0"
    :class="accordionTitleClasses")
    //- Expand icon on left.
    w-button.w-accordion__expand-icon(
      v-if="options.expandIcon && !options.expandIconRight"
      :icon="(accordionItem._expanded && options.collapseIcon) || options.expandIcon"
      :icon-props="options.expandIconProps"
      :disabled="accordionItem._disabled || null"
      :tabindex="-1"
      text
      @keypress.stop
      @click.stop="!accordionItem._disabled && toggleItem(accordionItem, $event)"
      :class="{ 'w-accordion__expand-icon--expanded': accordionItem._expanded, 'w-accordion__expand-icon--rotate90': options.expandIconRotate90 }")
    //- Title.
    slot(
      name="title"
      :item="getOriginalItem(accordionItem)"
      :expanded="accordionItem._expanded"
      :index="accordionItem._index + 1")
      .grow(v-html="accordionItem[options.itemTitleKey]")
    //- Expand icon on right.
    w-button.w-accordion__expand-icon(
      v-if="options.expandIcon && options.expandIconRight"
      :icon="(accordionItem._expanded && options.collapseIcon) || options.expandIcon"
      text
      @keypress.stop
      @click.stop="!accordionItem._disabled && toggleItem(accordionItem, $event)"
      :class="{ 'w-accordion__expand-icon--expanded': accordionItem._expanded, 'w-accordion__expand-icon--rotate90': options.expandIconRotate90 }")
  //- Content.
  //- keepInDom: content stays mounted; v-show toggles visibility (keep-alive is inactive, like w-tabs).
  w-transition-expand(
    v-if="options.keepInDom"
    y
    @after-leave="onEndOfCollapse(accordionItem)"
    :duration="options.duration")
    accordion-content(
      v-show="accordionItem._expanded"
      :item="accordionItem"
      :class="contentClasses")
      slot(
        v-if="$slots.content"
        name="content"
        :item="getOriginalItem(accordionItem)"
        :expanded="accordionItem._expanded"
        :index="accordionItem._index + 1")
        div(v-html="accordionItem[options.itemContentKey]")
      slot(
        v-else
        name="default"
        :item="getOriginalItem(accordionItem)"
        :expanded="accordionItem._expanded"
        :index="accordionItem._index + 1")
        div(v-html="accordionItem[options.itemContentKey]")
  w-transition-expand(
    v-else
    y
    @after-leave="onEndOfCollapse(accordionItem)"
    :duration="options.duration")
    keep-alive(:exclude="options.keepAlive ? '' : 'accordion-content'")
      accordion-content(
        v-if="accordionItem._expanded"
        :key="accordionItem._cuid"
        :item="accordionItem"
        :class="contentClasses")
        slot(
          v-if="$slots.content"
          name="content"
          :item="getOriginalItem(accordionItem)"
          :expanded="accordionItem._expanded"
          :index="accordionItem._index + 1")
          div(v-html="accordionItem[options.itemContentKey]")
        slot(
          v-else
          name="default"
          :item="getOriginalItem(accordionItem)"
          :expanded="accordionItem._expanded"
          :index="accordionItem._index + 1")
          div(v-html="accordionItem[options.itemContentKey]")
</template>

<script>
import { useId } from 'vue'
import RippleMixin from '../../mixins/ripple'
import { isRippleEnabled } from '../../utils/ripple'
import AccordionContent from './accordion-content.vue'
import { focusElement } from '../../utils/focus'

export default {
  name: 'w-accordion-item',
  focusable: true,
  expose: ['focus'],
  mixins: [RippleMixin],

  setup () {
    return { accordionItemUid: useId() }
  },

  components: { AccordionContent },

  props: {
    title: { type: String },
    content: { type: String },
    expanded: { type: Boolean },
    disabled: { type: Boolean }
  },

  inject: {
    options: { from: 'options' },
    titleClasses: { from: 'titleClasses' },
    contentClasses: { from: 'contentClasses' },
    expandedClass: { from: 'expandedClass' },
    onItemToggle: { from: 'onItemToggle' },
    onEndOfCollapse: { from: 'onEndOfCollapse' },
    getOriginalItem: { from: 'getOriginalItem' },
    getAccordionItem: { from: 'getAccordionItem' },
    registerItem: { from: 'registerItem' },
    unregisterItem: { from: 'unregisterItem' },
    getAccordionNoRipple: { from: 'getAccordionNoRipple', default: () => undefined }
  },

  emits: ['focus'],

  computed: {
    /** Per-item noRipple override, else parent `w-accordion` noRipple, else global config. */
    rippleActive () {
      let resolvedNoRipple
      if (typeof this.noRipple === 'boolean') resolvedNoRipple = this.noRipple
      else {
        const p = this.getAccordionNoRipple?.()
        resolvedNoRipple = typeof p === 'boolean' ? p : undefined
      }
      return isRippleEnabled(resolvedNoRipple ? false : undefined, this.$waveui)
    },

    accordionTitleClasses () {
      return {
        ...this.titleClasses,
        'w-ripple': this.rippleActive
      }
    },

    accordionItem: {
      get () {
        return this.getAccordionItem(this.accordionItemUid)
      },
      set () {}
    },
    itemClasses () {
      return {
        'w-accordion__item--expanded': this.accordionItem._expanded,
        'w-accordion__item--disabled': this.accordionItem._disabled,
        [this.accordionItem[this.options.itemColorKey]]: this.accordionItem[this.options.itemColorKey],
        [this.expandedClass]: this.accordionItem._expanded
      }
    }
  },

  methods: {
    focus () {
      if (this.accordionItem._disabled) return
      focusElement(this.$el.querySelector('.w-accordion__item-title'))
    },

    onAccordionTitlePointerDown (e) {
      if (this.accordionItem._disabled) return
      if (e.target.closest?.('.w-accordion__expand-icon')) return
      this.onRipple(e)
    },

    toggleItem (item, e) {
      item._expanded = !item._expanded

      this.onItemToggle(item)

      // When a focused item moves in the page, the scrollTop is naturally updated by the browser.
      // So if expandSingle is set to true, clicking on the next title of an open pane would shift the
      // scrollTop unless unfocused while transitioning. Issue #3.
      e.target.blur()
      setTimeout(() => e.target.focus(), 300)
    }
  },

  created () {
    // Register this item to the w-accordion component.
    this.registerItem({
      _cuid: this.accordionItemUid,
      _index: 0,
      _expanded: this.expanded,
      _disabled: this.disabled,
      title: this.title,
      content: this.content
    })
  },

  beforeUnmount () {
    this.unregisterItem(this.accordionItemUid)
  }
}
</script>

<style lang="scss">
.w-accordion__item {position: relative;}

button.w-accordion__expand-icon {color: color-mix(in srgb, var(--w-base-color) 40%, transparent);}
.w-accordion__expand-icon {
  margin-right: var(--w-base-increment);

  .w-accordion--rotate-icon & {@include default-transition;}
  &--rotate90 {transform: rotate(-90deg);}
  &--expanded {transform: rotate(-180deg);}
  &--expanded.w-accordion__expand-icon--rotate90 {transform: rotate(0deg);}

  .w-icon:before {font-size: 1.1em;}
}

.w-accordion__item-title {
  position: relative;
  display: flex;
  align-items: center;
  font-size: round(nearest, calc(1.2 * var(--w-base-font-size)), 1px);
  padding: var(--w-base-increment);
  user-select: none;
  cursor: pointer;
  border-top: var(--w-border);
  -webkit-tap-highlight-color: transparent;

  .w-accordion__item--disabled & {
    cursor: not-allowed;
    opacity: 0.6;
    -webkit-tap-highlight-color: transparent;
  }
  .w-accordion--no-icon &, .w-accordion--icon-right & {padding-left: calc(var(--w-base-increment) * 3);}

  .w-accordion__item:first-child & {border-top-color: transparent;}

  &:before {
    content: '';
    position: absolute;
    inset: 0;
    background-color: transparent;
    transition: background-color var(--w-transition-duration-fast);
    pointer-events: none;
  }

  &:focus:before, &:hover:before {background-color: color-mix(in srgb, currentColor 3%, transparent);}
  &:active:before {background-color: color-mix(in srgb, currentColor 5%, transparent);}
  .w-accordion__item--disabled &:before {display: none;}
}

.w-accordion__item-content {
  padding: calc(var(--w-base-increment) * 2) calc(var(--w-base-increment) * 3);
}
</style>
