<template>
  <PullRefresh
    v-model="refreshing"
    @refresh="onRefresh"
    :success-text="refreshingSussessText"
    :success-duration="pullRefreshSuccessDuration"
    :animation-duration="pullRefreshAnimationDuration"
    :head-height="pullRefreshHeight"
    :pull-distance="pullRefreshDistance"
    :disabled="pullRefreshDisabled"
  >
    <List
      ref="list"
      class="list"
      v-model="loading"
      :offset="loadMoreOffset"
      :finished="loadFinish"
      :error.sync="isError"
      @load="onLoadMore"
    >
      <slot :data="list"></slot>

      <!-- 加载更多提示 -->
      <template v-slot:loading>
        <slot name="load-more-loading"></slot>
      </template>

      <!-- 加载结束提示, 自己判断size -->
      <template v-slot:finished>
        <slot name="load-more-finished" :size="list.length"></slot>
      </template>

      <!-- 加载失败提示 -->
      <template v-slot:error>
        <slot name="load-more-error"></slot>
      </template>
    </List>

    <!-- 加载结束提示 -->
    <template v-slot:success>
      <slot name="pull-refresh-finish" :error="refreshingError"></slot>
    </template>

    <!-- 非下拉状态提示 -->
    <template v-slot:normal>
      <slot name="pull-refresh-normal" :error="refreshingError"></slot>
    </template>

    <!-- 下拉中提示 -->
    <template v-slot:pulling="{ distance }">
      <slot
        name="pull-refresh-pulling"
        :error="refreshingError"
        :distance="distance"
      />
    </template>

    <!-- 释放过程中提示 -->
    <template v-slot:loosing="{ distance }">
      <slot name="pull-refresh-loosing" :distance="distance" />
    </template>

    <!-- 加载中提示 -->
    <template v-slot:loading="{ distance }">
      <slot name="pull-refresh-finish" :distance="distance" />
    </template>
  </PullRefresh>
</template>

<script lang="ts">
import Vue from 'vue';
import { List, PullRefresh } from '../vant';
import { Lock, logger } from '../utils';

const lock = new Lock();

export default Vue.extend({
  components: {
    List,
    PullRefresh,
  },
  props: {
    /**
     * 获取数据的函数
     * @type {Promise<any[]>}
     */
    getData: {
      type: Function,
      required: true,
    },

    /**
     * 是否支持下拉刷新
     */
    pullRefreshDisabled: {
      type: Boolean,
      default: false,
    },

    /**
     * 顶部高度
     */
    pullRefreshHeight: {
      type: Number,
      default: 50,
    },

    /**
     * 触发下拉刷新的距离
     */
    pullRefreshDistance: {
      type: Number,
      default: 50,
    },

    /**
     * 刷新动画时长
     */
    pullRefreshAnimationDuration: {
      type: Number,
      default: 300,
    },

    /**
     * 刷新成功提示时长
     */
    pullRefreshSuccessDuration: {
      type: Number,
      default: 500,
    },

    /**
     * 距离底部的高度小于 `loadMoreOffset` 时，触发加载更多
     */
    loadMoreOffset: {
      type: Number,
      default: 300,
    },

    /**
     * 是否支持上拉加载
     */
    // pullUpDisabled: {
    //   type: Boolean,
    //   default: false,
    // },
  },
  data() {
    return {
      /**
       * 刷新状态
       */
      refreshing: false,

      /**
       * 是否刷新失败
       */
      refreshingError: false,

      /**
       * 加载状态
       */
      loading: false,

      /**
       * 加载结束状态,没有更多数据
       */
      loadFinish: false,

      /**
       * 是否加载失败
       */
      isError: false,

      /**
       * 分页参数
       */
      page: 1,

      /**
       * 存数据的，外面不用管
       */
      list: [],
    };
  },
  computed: {
    /**
     * 刷新结束文字
     */
    refreshingSussessText() {
      if (this.refreshingError) {
        return '刷新失败，请重新刷新';
      }
      return '刷新成功';
    },
  },
  methods: {
    async onRefresh() {
      try {
        await lock.lock();
        this.refreshingError = false;
        this.loadFinish = false;
        this.isError = false;
        this.page = 1;
        let data = await this.getData(this.page);
        this.page++;
        this.list = data;

        // 如果刷新之后没数据了
        if (0 == data.length) {
          this.loadFinish = true;
        }

        /**
         * 可能第一页的数据不够，需要检查一下是否触发下一页
         */
        (this.$refs.list as any).check();
      } catch (e) {
        logger.error(e);
        this.refreshingError = true;
        this.$emit('error', this.refreshingSussessText);
      } finally {
        this.refreshing = false;
        lock.unlock();
      }
    },
    async onLoadMore() {
      try {
        await lock.lock();
        this.isError = false;
        let data = await this.getData(this.page);
        if (0 == data.length) {
          this.loadFinish = true;
        } else {
          // @ts-ignore
          this.list.push(...data);
          this.page++;
        }
      } catch (e) {
        logger.error(e);
        this.isError = true;
      } finally {
        this.loading = false;
        lock.unlock();
      }
    },
  },
});
</script>

<style lang="scss" scoped>
.list {
  padding-bottom: 150px;
}
</style>
