<template>
  <div class="tn-swipe">
    <div class="tn-swipe__content" :style="swipeStyle" ref="swipe" @touchstart="onTouchStart" @touchmove="onTouchMove" @touchend="onTouchEnd" @click.capture="onClickWrap">
      <slot></slot>
    </div>
    <ul class="tn-swipe__btns" :style="swipeStyle" ref="btns">
      <li class="tn-swipe__btn" :style="btn.style" ref="btn" v-for="(btn, index) in btns" :key="index" @click.prevent="onClickBtn(btn)">
        <span class="tn-swipe__btn-text">{{btn.text}}</span>
      </li>
    </ul>
  </div>
</template>

<script lang="ts">
import Vue, { PropOptions } from 'vue'
// import TouchEvents from '../../Touch'
// Vue.use(TouchEvents)

const DIRACTION_RIGHT = 1
const DIRACTION_LEFT = -1

export default Vue.extend({
  name: 'TnSwipe',

  props: {
    // 标识 id
    id: {
      type: [Number, String],
      default: -1
    },
    // 禁用
    disabled: {
      type: Boolean,
      default: false
    },
    // 按钮组
    btns: {
      type: Array,
      default: () => [
        { text: '删除', type: 'delete' }
      ]
    } as PropOptions<any[]>,
    type: {
      type: String,
      default: 'inside'
    }
  },

  data () {
    return {
      startX: 0, // 开始 x 坐标
      startY: 0, // 开始 y 坐标
      moveX: 0, // 移动 x 坐标
      moveY: 0, // 移动 y 坐标
      distX: 0, // 移动的距离 x
      distY: 0, // 移动的距离 y
      absX: 0, // 绝对值 移动的距离 x
      absY: 0, // 绝对值 移动的距离 y
      diraction: 0, // 1=右滑, -1=左滑
      distLockThreshold: 5, // 所动移动方向阈值
      isSwiping: false, // 是否是 swipe
      isMoved: false, // 是否移动
      isShow: false, // 按钮是否处于显示状态
      resetTimer: null as any, // 重置 timer
      btnSize: 80, // btn 的宽度
      swipeStyle: {}, // swipe 样式
    }
  },

  watch: {
    btns () {
      this.refresh()
    },
    disabled (val, oldVal) {
      if (val && val !== oldVal) {
        this.refresh()
      }
    }
  },

  methods: {
    onTouchStart (e) {
      if (this.disabled) {
        return
      }
      this.$emit('start', this.id)
      this.isMoved = false
      this.isSwiping = true
      const point = e.touches[0]
      this.startX = point.pageX
      this.startY = point.pageY
      this.distX = 0
      this.distY = 0
      if (this.isShow) {
        this.resetTimer = setTimeout(this.resetPos, 300)
      }
    },
    onTouchMove (e) {
      if (this.disabled) {
        e.stopPropagation()
        return
      }
      if (this.isMoved) {
        clearTimeout(this.resetTimer) // 如果已经移动，清除 timer
      }
      if (this.isShow) {
        e.stopPropagation()
      }

      if (!this.isSwiping) {
        return
      }

      const point = e.touches[0]
      this.moveX = point.pageX
      this.moveY = point.pageY
      this.distX = this.moveX - this.startX
      this.distY = this.moveY - this.startY
      this.absX = Math.abs(this.distX)
      this.absY = Math.abs(this.distY)

      // 如果 x 移动距离小于 y 的距离，认为是在滚动
      if (this.absX + this.distLockThreshold <= this.absY || this.distX > 0 || this.absY > 18) {
        this.isSwiping = false
        return
      }
      if (e.cancelable) {
        e.preventDefault()
      }
      this.isSwiping = true
      if (!this.isMoved) {
        if (this.$parent.$options.name === 'TnSwipeGroup') {
          const swipeGroup: any = this.$parent
          swipeGroup.closeOthers(this)
        }
        this.isMoved = true
      }
      this.diraction = this.distX > 0 ? DIRACTION_RIGHT : this.distX < 0 ? DIRACTION_LEFT : 0
      this.calcPos(this.distX)
      this.$emit('move', this.distX)
    },
    onTouchEnd (e) {
      if (this.disabled || !this.isMoved) {
        return
      }
      let dist = this.distX
      if (this.isShow) {
        if (this.distX >= this.btnSize / 2) {
          dist = 0
        } else {
          dist = -this.btnSize
        }
      } else {
        if (this.distX <= -this.btnSize / 2) {
          dist = -this.btnSize
        } else {
          dist = 0
        }
      }
      this.changePos(dist)
      this.$emit('end', this.id)
      e.preventDefault()
    },
    onClickBtn (btn) {
      this.$emit('btnClick', btn)
    },
    onClickWrap (e) {
      if (this.isShow) {
        e.stopPropagation()
      }
    },
    // 计算位置
    calcPos (dist) {
      // 不超过最大移动距离
      if (dist > this.btnSize) {
        dist = this.btnSize
      } else if (dist < -this.btnSize) {
        dist = -this.btnSize
      }
      if (this.diraction === DIRACTION_RIGHT) {
        if (this.isShow) {
          dist = this.btnSize - dist
        } else {
          dist = 0
        }
      } else {
        if (this.isShow) {
          dist = -this.btnSize
        }
      }
      this.changePos(dist)
      this.isShow = dist < 0
    },
    // 更改按钮位置
    changePos (dist) {
      this.swipeStyle = {
        transform: `translate(${dist}px, 0)`
      }
    },
    // 重置按钮位置
    resetPos () {
      this.changePos(0)
      this.isShow = false
    },
    // 计算按钮宽度
    refresh () {
      this.$nextTick(() => {
        const ref: any = this.$refs.btns
        this.isShow = false
        this.btnSize = ref.offsetWidth
        this.resetPos() // 需要重置位置
      })
    },
  },

  mounted () {
    this.refresh()
  },
  beforeDestroy () {
    // clearTimeout(this.resetTimer)
  }
})
</script>

<style lang="stylus">
@import '../../../style/swipe.styl';
</style>
