<template>
  <VTabs
    v-model="selectedTabIndex"
    v-bind="[tabGroupAttrs, $attrs]"
    class="pitcher-filter-tab rounded-lg"
    @change="filterSelected"
  >
    <div ref="slider" class="tabs-background-slider">
      <div class="slider-box rounded" />
    </div>
    <VTab v-for="item in mapItems" ref="tabRefs" :key="item.value" v-bind="tabProps" :disabled="item.disabled">
      <VBtn class="tab-button" text :color="getActiveColor(item)">
        <template v-if="item.icon && !item.iconRight">
          <VIcon class="mr-3">{{ item.icon }}</VIcon>
        </template>
        {{ item.text }}
        <VBadge
          v-if="item.description"
          v-bind="badgeAttrs"
          :content="item.description"
          :color="getActiveColor(item, 'transparent')"
        />
        <template v-if="item.icon && item.iconRight">
          <VIcon class="ml-3">{{ item.icon }}</VIcon>
        </template>
      </VBtn>
    </VTab>
  </VTabs>
</template>

<script>
import { computed, onBeforeUnmount, onMounted, onUpdated, reactive, toRefs } from '@vue/composition-api'
import { vuetifyColorMapper } from '../../utils'
/* 
* props *
By default, you can use all v-tabs props on this component

* Object model for item (button) in items array *
item: {
  text:        String => required
  value:       String => required
  icon:        String => not required, any FA icon, e.g. fa fa-user
  description: String => not required, description is the text inside badge
}

* Mapping item props for text/value *
If you have any other model than this for your text or value,
you can easily use item-text="PROP_NAME" item-value="PROP_NAME" to map those as text/value

* Changing emit return type *
If you need to emit the whole object on input, use return-object prop

* Editing badge, tab props externally *
To be able to edit v-tab, v-badge etc. you can use
tab-props="V-Tab Props", badge-props="V-Badge Props"
*/

/**
 * Pitcher Filter Tab component
 * @inherits v-tabs
 */

export default {
  name: 'PFilterTab',
  inheritAttrs: false,
  props: {
    value: {
      type: [Object, String],
      default: undefined,
    },
    items: {
      type: Array,
      default: () => [],
    },
    mandatory: {
      type: Boolean,
      default: true,
    },
    activeColor: {
      type: String,
      default: 'primary',
    },
    itemValue: {
      type: String,
      default: 'value',
    },
    itemText: {
      type: String,
      default: 'text',
    },
    returnObject: {
      type: Boolean,
      default: false,
    },
    tabProps: {
      type: Object,
      default: () => ({
        class: {
          rounded: true,
        },
      }),
    },
    badgeProps: {
      type: Object,
      default: () => ({}),
    },
  },
  emits: ['input'],
  setup(props, ctx) {
    const state = reactive({
      selectedTabIndex: undefined,
    })

    const tabGroupAttrs = computed(() => ({
      backgroundColor: ctx.attrs['background-color'] || 'grey lighten-3',
      showArrows: true,
      grow: true,
      hideSlider: true,
      optional: !props.mandatory,
      height: '40px',
    }))

    const badgeAttrs = computed(() => ({
      class: {
        'ml-1': true,
        'has-active-color': !!props.activeColor,
      },
      inline: true,
      ...props.badgeProps,
    }))

    const mapItems = computed(() =>
      props.items.map((item) => {
        // eslint-disable-next-line eqeqeq
        if (item.constructor == Object) {
          return {
            text: item[props.itemText],
            value: item[props.itemValue],
            icon: item.icon,
            disabled: item.disabled,
            description: item.description,
            selected: isSelected(item),
          }
        } else {
          return {
            text: item,
            value: item,
            selected: isSelected(item),
          }
        }
      })
    )

    // Emit when selected
    const filterSelected = (index) => {
      if (typeof index === 'undefined') {
        ctx.emit('input', index)

        return
      }

      // parse item without reactivity
      const item = JSON.parse(JSON.stringify(props.items[index]))

      ctx.emit('input', props.returnObject ? item : item[props.itemValue] || item)
    }

    // to determine current selection
    const isSelected = (item) => {
      if (!props.value) return false
      if (item.constructor !== Object) return props.value === item

      return props.returnObject
        ? props.value[props.itemValue] === item[props.itemValue]
        : props.value === item[props.itemValue]
    }

    const getActiveColor = (item, fallback = undefined) =>
      item.selected && props.activeColor ? vuetifyColorMapper(props.activeColor) : fallback

    const isIE11 = !!window.MSInputMethodContext && !!document.documentMode
    const setSliderStyle = () => {
      // Find index of current value
      // props.value && props.value[props.itemValue] finds if returnObject is true
      // otherwise just returns props.value as it is not an object
      const index = mapItems.value.findIndex(
        (item) => item.value === ((props.value && props.value[props.itemValue]) || props.value)
      )

      // hide if no value, no tabRefs or slider available
      if (index < 0 || !ctx.refs.tabRefs || !ctx.refs.slider) {
        // fade out on unselect if not mandatory
        ctx.refs.slider.style.opacity = 0

        return
      }

      // get current tab element
      const el = ctx.refs.tabRefs[index].$el

      // set styles
      // [IE11 compatibility], getComputedStyle gives wrong width
      ctx.refs.slider.style.opacity = 1
      ctx.refs.slider.style.width = isIE11 ? `${el.offsetWidth}px` : getComputedStyle(el).width
      ctx.refs.slider.style.transform = `translateX(${el.offsetLeft}px)`
    }

    onMounted(() => window.addEventListener('resize', setSliderStyle))
    onBeforeUnmount(() => window.removeEventListener('resize', setSliderStyle))
    onUpdated(() => setSliderStyle())

    return {
      ...toRefs(state),
      mapItems,
      tabGroupAttrs,
      badgeAttrs,
      filterSelected,
      getActiveColor,
    }
  },
}
</script>

<style lang="scss" scoped>
.pitcher-filter-tab {
  .tabs-background-slider {
    position: absolute;
    top: 0;
    left: 0;
    height: 100%;
    padding: 4px;
    transition: 0.3s cubic-bezier(0.33, 1, 0.68, 1);
    transform: translateX(0%);
    z-index: 0;

    .slider-box {
      background-color: #fff;
      height: 100%;
    }
  }
  ::v-deep {
    .v-slide-group {
      // for light theme
      &.theme--light {
        .v-tab {
          &:not(.v-tab--active) {
            color: rgba(0, 0, 0, 0.5) !important;
          }
        }
      }

      .v-tab {
        .tab-button::before {
          background-color: transparent;
          display: none;
        }

        &--active {
          // background-color: #fff;
          color: map-deep-get($material-light, 'text', 'primary');

          // Active badge colors when no props.activeColor
          .v-badge {
            .v-badge__badge {
              color: #fff !important;
            }

            &:not(.has-active-color) .v-badge__badge {
              background-color: map-deep-get($material-light, 'text', 'primary') !important;
            }
          }
        }

        // disabled tab
        &--disabled {
          opacity: 0.4;
        }

        &:hover::before {
          opacity: 0;
        }

        &::before {
          border-radius: inherit;
        }

        // icon color override
        i {
          color: inherit !important;
        }

        // Badge default overrides
        .v-badge {
          opacity: 0.9;

          &__badge {
            color: inherit;
            pointer-events: none;
          }
        }
      }
    }
  }
}
</style>
