<template>
  <div :class="qTabsClasses">
    <div
      ref="tabs"
      :style="{ width: width, 'min-width': width, 'max-width': width }"
      :class="qTabsInnerClasses"
    >
      <slot name="title" />
      <div :class="qTabsPosbarClasses">
        <div
          ref="posbar"
          :class="qTabsPosbarInnerClasses"
          @transitionend="__updatePosbarTransition"
        ></div>
      </div>
    </div>
    <div :class="qTabsPanesClasses">
      <slot />
    </div>
  </div>
</template>

<script lang="ts">
// @ts-nocheck
import { WidgetWrapper } from '@devsun/form-generator/dist';
import { Component, Prop, Provide, Vue } from 'vue-property-decorator';
import { QTabs } from 'quasar';

function getUnderlineClass(v) {
  if (v) {
    return `text-${v}`;
  }
}

@Component({
  components: {
    WidgetWrapper,
    QTabs,
  },
})
export default class HorizontalTabs extends Vue {
  @Prop() private inverted: boolean;
  @Prop() private twoLines: boolean;
  @Prop({ default: 'left' }) private align:
    | 'left'
    | 'right'
    | 'center'
    | 'justify';
  @Prop({ default: 'primary' }) private color: string;
  @Prop() private textColor: string;

  @Prop() private value: any; // different value in qtabs - for vmodel there
  @Prop({ default: 'secondary' }) private underlineColor: string;

  @Prop({ default: true }) private animated: boolean;
  @Prop({ default: '220px ' }) private width: string;

  @Provide()
  private data: any = {
    highlight: true,
    tabName: this.value || '',
    color: this.color,
    textColor: this.textColor,
    inverted: this.inverted,
    underlineClass: getUnderlineClass(this.underlineColor),
    direction: null,
  };

  private currentEl: any = null;
  private oldEl: any = null;
  private posbar = {
    // probably should be height and bottom if we are going for vertical indicator
    width: 0,
    height: 0,
    left: 0,
    top: 0,
  };
  private finalPosbar: any = null;

  private timer: any = null;
  private scrollTimer: any = null;
  private bufferTimer: any = null;
  private buffer: any[] = [];

  private get qTabsClasses() {
    return [
      'q-tabs',
      'column',
      'no-wrap',
      `q-tabs-${this.inverted ? 'inverted' : 'normal'}`,
      this.twoLines ? 'q-tabs-two-lines' : '',
    ];
  }

  private get qTabsInnerClasses() {
    const cls = ['q-tabs-head', `q-tabs-align-${this.align}`];
    if (this.inverted) {
      cls.push(`text-${this.textColor || this.color}`);
    } else {
      cls.push(`bg-${this.color}`);
      cls.push(`text-${this.textColor || 'white'}`);
    }
    return cls;
  }

  private get qTabsPosbarClasses() {
    const cls = [
      'relative-position',
      'self-stretch',
      'q-tabs-global-bar-container',
    ];
    if (this.inverted) {
      cls.push(`text-${this.textColor || this.color}`);
    }
    if (this.data.highlight) {
      cls.push('highlight');
    }

    return cls;
  }

  private get qTabsPosbarInnerClasses() {
    const cls = ['q-tabs-bar', 'q-tabs-global-bar'];

    // tslint:disable-next-line
    this.data.underlineClass && cls.push(this.data.underlineClass);
    return cls;
  }

  private get qTabsPanesClasses() {
    return ['q-tabs-panes', 'col'];
  }

  __getTabElByName(value) {
    const tab = this.$children.find(
      (child: any) =>
        child.name === value && child.$el && child.$el.nodeType === 1
    );
    if (tab) {
      return tab.$el;
    }
  }

  __repositionBar() {
    clearTimeout(this.timer);

    let needsUpdate = false;
    const ref: any = this.$refs.posbar;
    const el = this.currentEl;

    if (this.data.highlight !== false) {
      this.data.highlight = false;
      needsUpdate = true;
    }

    if (!el) {
      this.finalPosbar = { width: 0, left: 0, top: 0, height: 0 };
      this.__setPositionBar(0, 0, 0, 0);
      return;
    }

    const offsetLeftReference = ref.parentNode.offsetLeft;
    const offsetTopReference = ref.parentNode.offsetTop;

    if (needsUpdate && this.oldEl) {
      this.__setPositionBar(
        this.oldEl.getBoundingClientRect().width,
        this.oldEl.offsetLeft - offsetLeftReference,
        this.oldEl.offsetTop - offsetTopReference,
        this.oldEl.getBoundingClientRect().height
      );
    }

    this.timer = setTimeout(() => {
      const width = el.getBoundingClientRect().width;
      const height = el.getBoundingClientRect().height;

      const left = el.offsetLeft - offsetLeftReference;
      const top = el.offsetTop - offsetTopReference;

      ref.classList.remove('contract');
      this.oldEl = el;
      this.finalPosbar = { width, left, top, height };

      this.__setPositionBar(
        this.posbar.left < left
          ? left + width - this.posbar.left
          : this.posbar.left + this.posbar.width - left,
        this.posbar.left < left ? this.posbar.left : left,
        this.posbar.top < top ? this.posbar.top : top,
        height
      );
    }, 20);
  }

  __setPositionBar(width = 0, left = 0, top = 0, height = 0) {
    if (
      this.posbar.width === width &&
      this.posbar.left === left &&
      this.posbar.top === top
    ) {
      this.__updatePosbarTransition();
      return;
    }

    this.posbar = { width, left, top, height };
    const xPos = /*this.$q.i18n.rtl
                ? left + width
                : /**/ left;

    const yPos = top + height;

    (this.$refs
      .posbar as any).style.transform = `scaleX(${width}) translate(0, ${yPos}px)`;
  }

  __updatePosbarTransition() {
    if (
      this.finalPosbar &&
      this.finalPosbar.width === this.posbar.width &&
      this.finalPosbar.left === this.posbar.left &&
      this.finalPosbar.top === this.posbar.top &&
      this.finalPosbar.height === this.posbar.height
    ) {
      (this.posbar as any) = {};
      if (this.data.highlight !== true) {
        this.data.highlight = true;
      }
      return;
    }

    (this.$refs.posbar as any).classList.add('contract');
    if (this.finalPosbar) {
      this.__setPositionBar(
        this.finalPosbar.width,
        this.finalPosbar.left,
        this.finalPosbar.top,
        this.finalPosbar.height
      );
    }
  }

  @Provide()
  selectTab(value) {
    if (this.data.tabName === value) {
      return;
    }

    this.data.tabName = value;
    const el = this.__getTabElByName(value);

    if (el) {
      // this.__scrollToTab(el)
      // I've removed everything referring to scroll. Though it is likely that there would be tabs requiring it
      // for now it is just uncalled for

      this.currentEl = el;

      if (this.oldEl) {
        if (this.animated) {
          const children = (this.$refs.tabs as any).children;
          this.data.direction =
            Array.prototype.indexOf.call(children, el) <
            Array.prototype.indexOf.call(children, this.oldEl)
              ? 'top'
              : 'bottom';
        }

        this.__repositionBar();
      } else {
        this.oldEl = el;
      }
    } else {
      this.oldEl = null;
      this.data.direction = null;
    }

    this.$emit('input', value, this.data.direction);
    this.$emit('select', value, this.data.direction);
  }

  @Provide()
  selectTabRouter(params) {
    const { value, selectable, exact, selected, priority } = params;
    const first = !this.buffer.length;
    const existingIndex = first
      ? -1
      : this.buffer.findIndex((t) => t.value === value);

    if (existingIndex > -1) {
      const buffer = this.buffer[existingIndex];
      /* tslint:disable */
      exact && (buffer.exact = exact);
      selectable && (buffer.selectable = selectable);
      selected && (buffer.selected = selected);
      priority && (buffer.priority = priority);
      /* tslint:enable */
    } else {
      this.buffer.push(params);
    }

    if (first) {
      this.bufferTimer = setTimeout(() => {
        const tab =
          this.buffer.find((t) => t.exact && t.selected) ||
          this.buffer.find((t) => t.selectable && t.selected) ||
          this.buffer.find((t) => t.exact) ||
          this.buffer
            .filter((t) => t.selectable)
            .sort((t1, t2) => t2.priority - t1.priority)[0] ||
          this.buffer[0];

        this.buffer.length = 0;
        this.selectTab(tab.value);
      }, 100);
    }
  }

  private created() {
    this.timer = null;
    this.scrollTimer = null;
    this.bufferTimer = null;
    this.buffer = [];
  }

  mounted() {
    this.$nextTick(() => {
      if (this.data.tabName !== '' && this.value) {
        this.selectTab(this.value);
      }
    });
  }

  // hide this

  beforeDestroy() {
    clearTimeout(this.timer);
    clearTimeout(this.bufferTimer);
  }

  @Prop() private model: any;
  @Prop() private schema: any;
}
</script>

<style scoped>
.q-tabs {
  flex-direction: row;
  border-radius: 3px;
}

.q-tabs-global-bar-container.highlight > .q-tabs-global-bar {
  /* for some reason in quasar this is display: none */
  display: initial;
}

.q-tabs-bar {
  bottom: 0;
  border-right-width: 2px;
}

.q-tab.active {
  border: 0 solid;
  border-bottom-width: 2px;
}
</style>
