import { VantComponent } from '../common/component';
import { touch } from '../mixins/touch';
import {
  getAllRect,
  getRect,
  groupSetData,
  nextTick,
  requestAnimationFrame,
} from '../common/utils';
import { isDef } from '../common/validator';
VantComponent({
  mixins: [touch],
  classes: ["nav-class", "tab-class", "tab-active-class", "line-class"],
  relation: {
    name: "tab",
    type: "descendant",
    current: "tabs",
    linked(target) {
      target.index = this.children.length - 1;
      this.updateTabs();
    },
    unlinked() {
      this.children = this.children.map((child, index) => {
        child.index = index;
        return child;
      });
      this.updateTabs();
    }
  },
  props: {
    sticky: Boolean,
    border: Boolean,
    swipeable: Boolean,
    titleActiveColor: String,
    titleInactiveColor: String,
    color: String,
    animated: {
      type: Boolean,
      observer() {
        this.children.forEach((child, index) =>
          child.updateRender(index === this.data.currentIndex, this)
        );
      }
    },
    lineWidth: {
      type: [String, Number],
      value: 40,
      // observer: "resize"
    },
    lineLengthType: {
      type: [String, Number],
      value: 1  // 1默认自适应 2短自适应 3 固定宽度取值lineWidth
    },
    linePosition: {
      type: [String, Number],
      value: 1  // 1默认右对齐 2居中 3铺满
    },
    lineHeight: {
      type: [String, Number],
      value: -1
    },
    active: {
      type: [String, Number],
      value: 0,
      observer(name) {
        if (name !== this.getCurrentName()) {
          this.setCurrentIndexByName(name);
        }
      }
    },
    type: {
      type: String,
      value: "line"
    },
    ellipsis: {
      type: Boolean,
      value: true
    },
    duration: {
      type: Number,
      value: 0.3
    },
    zIndex: {
      type: Number,
      value: 1
    },
    swipeThreshold: {
      type: Number,
      value: 5,
      observer(value) {
        this.setData({
          scrollable: this.children.length > value || !this.data.ellipsis
        });
      }
    },
    offsetTop: {
      type: Number,
      value: 0
    },
    lazyRender: {
      type: Boolean,
      value: true
    }
  },
  data: {
    tabs: [],
    scrollLeft: 0,
    scrollable: false,
    currentIndex: 0,
    container: null,
    skipTransition: true,
    lineOffsetLeft: 0
  },
  mounted() {
    this.getElementInfo();
    requestAnimationFrame(() => {
      this.setData({
        container: () => this.createSelectorQuery().select(".van-tabs")
      });
      this.resize(true);
      this.scrollIntoView();
    });
  },
  methods: {
    getElementInfo() {
      let that = this;
      wx
        .createSelectorQuery()
        .in(this)
        .selectAll(".van-tab")
        .boundingClientRect()
        .exec((rect = []) =>
          that.triggerEvent("getEleInfo", { rect, vanTabsThis: this })
        );
    },
    updateTabs() {
      const { children = [], data } = this;
      this.setData({
        tabs: children.map(child => child.data),
        scrollable: this.children.length > data.swipeThreshold || !data.ellipsis
      });
      this.setCurrentIndexByName(data.active || this.getCurrentName());
    },
    trigger(eventName, child) {
      const { currentIndex } = this.data;
      const currentChild = child || this.children[currentIndex];
      if (!isDef(currentChild)) {
        return;
      }
      this.$emit(eventName, {
        index: currentChild.index,
        name: currentChild.getComputedName(),
        title: currentChild.data.title
      });
    },
    onTap(event) {
      const { index } = event.currentTarget.dataset;
      const child = this.children[index];
      if (child.data.disabled) {
        this.trigger("disabled", child);
      } else {
        this.setCurrentIndex(index);
        nextTick(() => {
          this.trigger("click");
        });
      }
    },
    // correct the index of active tab
    setCurrentIndexByName(name) {
      const { children = [] } = this;
      const matched = children.filter(
        child => child.getComputedName() === name
      );
      if (matched.length) {
        this.setCurrentIndex(matched[0].index);
      }
    },
    setCurrentIndex(currentIndex) {
      const { data, children = [] } = this;
      if (
        !isDef(currentIndex) ||
        currentIndex >= children.length ||
        currentIndex < 0
      ) {
        return;
      }
      groupSetData(this, () => {
        children.forEach((item, index) => {
          const active = index === currentIndex;
          if (active !== item.data.active || !item.inited) {
            item.updateRender(active, this);
          }
        });
      });
      if (currentIndex === data.currentIndex) {
        return;
      }
      const shouldEmitChange = data.currentIndex !== null;
      this.setData({ currentIndex });
      nextTick(() => {
        this.resize();
        this.scrollIntoView();
        this.trigger("input");
        if (shouldEmitChange) {
          this.trigger("change");
        }
      });
    },
    getCurrentName() {
      const activeTab = this.children[this.data.currentIndex];
      if (activeTab) {
        return activeTab.getComputedName();
      }
    },
    resize(skipTransition = false) {
      console.log("resize")
      if (this.data.type !== "line") {
        return;
      }
      const { currentIndex, ellipsis } = this.data;
      Promise.all([
        getAllRect(this, ".van-tab"),
        getRect(this, ".van-tabs__line")
      ]).then(([rects = [], lineRect]) => {
        const rect = rects[currentIndex];
        if (rect == null) {
          return;
        }
        let lineWidths = 0;
        let lineOffsetLeft = 0;
        if (this.data.lineLengthType == 1) {
          if (this.data.linePosition == 2) {
            lineOffsetLeft = rect.left;
          } else {
            lineOffsetLeft = rects
              .slice(0, currentIndex)
              .reduce((prev, curr) => prev + curr.width, 0);
            lineOffsetLeft += 8;
          }
          lineWidths = rect.width;
        } else if (this.data.lineLengthType == 2) {
          // 宽度*80%
          if (this.data.linePosition == 2) {
            lineOffsetLeft = rect.left+rect.width*0.2;
          } else {
            lineOffsetLeft = rects
              .slice(0, currentIndex)
              .reduce((prev, curr) => prev + curr.width, 0);
            lineOffsetLeft += rect.width * 0.2;
            lineOffsetLeft += 8;
          }
          lineWidths = rect.width * 0.6;
        } else {
          // 有问题暂不支持固定宽度
          // lineOffsetLeft = rects
          //   .slice(0, currentIndex)
          //   .reduce((prev, curr) => prev + curr.width, 0);
          // lineOffsetLeft += this.data.lineWidth / 2;
          // lineWidths = this.data.lineWidth;
        }
        this.setData({
          lineWidth: lineWidths,
          lineOffsetLeft,
          skipTransition
        });
      });
    },
    // scroll active tab into view
    scrollIntoView() {
      const { currentIndex, scrollable } = this.data;
      if (!scrollable) {
        return;
      }
      Promise.all([
        getAllRect(this, ".van-tab"),
        getRect(this, ".van-tabs__nav")
      ]).then(([tabRects, navRect]) => {
        const tabRect = tabRects[currentIndex];
        const offsetLeft = tabRects
          .slice(0, currentIndex)
          .reduce((prev, curr) => prev + curr.width, 0);
        this.setData({
          scrollLeft: offsetLeft - (navRect.width - tabRect.width) / 2
        });
      });
    },
    onTouchScroll(event) {
      this.$emit("scroll", event.detail);
    },
    onTouchStart(event) {
      if (!this.data.swipeable) return;
      this.touchStart(event);
    },
    onTouchMove(event) {
      if (!this.data.swipeable) return;
      this.touchMove(event);
    },
    // watch swipe touch end
    onTouchEnd() {
      if (!this.data.swipeable) return;
      const { direction, deltaX, offsetX } = this;
      const minSwipeDistance = 50;
      if (direction === "horizontal" && offsetX >= minSwipeDistance) {
        const index = this.getAvaiableTab(deltaX);
        if (index !== -1) {
          this.setCurrentIndex(index);
        }
      }
    },
    getAvaiableTab(direction) {
      const { tabs, currentIndex } = this.data;
      const step = direction > 0 ? -1 : 1;
      for (
        let i = step;
        currentIndex + i < tabs.length && currentIndex + i >= 0;
        i += step
      ) {
        const index = currentIndex + i;
        if (
          index >= 0 &&
          index < tabs.length &&
          tabs[index] &&
          !tabs[index].disabled
        ) {
          return index;
        }
      }
      return -1;
    }
  }
});