<template>
  <view :style="{ height: height }" class="flex flex-col overflow-hidden u-font-14">
    <!-- 标题栏 -->
    <Title />

    <view class="container flex flex-col flex-1 mx-auto overflow-hidden bg-gray-100">
      <!-- 角色栏 -->
      <Roles />

      <!-- 日常任务面板 -->
      <Globals />

      <!-- 定期任务面板 -->
      <!-- <TimeLine @getTasks="getTasks" class="flex-1 overflow-hidden" ref="timeLine" /> -->
    </view>
  </view>
</template>

<script>
import { defineComponent, ref, onMounted, computed, watch, nextTick } from 'vue';
import { useStore } from 'vuex';
import { flatten } from 'lodash';

export default defineComponent({
  setup(options) {
    const store = useStore();
    const token = computed(() => store.state.user.token);
    const userId = computed(() => store.getters['user/userId']);
    const roleId = computed(() => store.state.role.roleId);
    const timeNode = computed(() => store.state.task.timeNode);
    const timeUnit = computed(() => store.state.task.timeUnit);
    const tasks = computed(() => store.state.task.tasks);
    const newProjectInfo = computed(() => store.state.task.newProjectInfo);
    const showScrollTo = computed(() => store.state.task.showScrollTo);
    const timeGranularity = computed(() => store.getters['task/timeGranularity']);
    const projectId = computed(() => store.getters['project/projectId']);
    const height = ref(null);
    const timeLine = ref(null);

    /**
     * 当时间基准点发生变化时
     * 重新根据时间和角色查询普通日常任务
     * 永久日常任务不发生 改变
     */
    watch(timeNode, newValue => {
      if (newValue && roleId.value) {
        clearTasksData();
        getGlobalData(); // 查可变日常任务
        initPlanTasks(); // 处理定期任务
      }
    });

    /**
     * 当角色发生变化时
     * 重新查询永久日常任务和普通日常任务
     * 注意: 切换角色后 重新设置了时间基准点 时间基准点一定会变
     * 所以监听时间基准点获取 可变日常任务即可 这里不用获取 避免重复获取
     */
    watch(roleId, newValue => {
      if (newValue) {
        store.commit('task/setTimeNode', Date.now());
        // 根据角色查找永久的日常任务
        const params = { roleId: newValue, projectId: projectId.value };
        store.dispatch('task/getPermanent', params);
      }
    });

    /**
     * 当时间基准点发生变化时
     * 重新根据时间和角色查询普通日常任务
     * 永久日常任务不发生改变
     */
    watch(newProjectInfo, newValue => {
      if (newValue && newValue.projectId && newValue.url) {
        uni.$u.route('/', { u: userId.value, p: newValue.projectId, url: newValue.url });
        clearTasksData();
        store.commit('role/setRoleId', '');
        const options = uni.$route.query;
        init(options);
      }
    });

    onMounted(() => {
      const system = uni.getSystemInfoSync();
      height.value = `${system.windowHeight}px`;
    });

    // 初始化 定期任务
    async function initPlanTasks() {
      setPrevPlaceholderTasks(); // 向上加载空数据
      setNextPlaceholderTasks(); // 向下加载空数据
      await getInitTasks(); // 获取初始数据

      // 滚动到对应位置
      let timer = null;
      timer = setInterval(() => {
        if (showScrollTo.value) {
          clearInterval(timer);
          // nextTick(() => timeLine.setScrollPosition());
        }
      }, 500);
    }

    // 切换了 颗粒度 || 角色时候 获取初始定期任务
    function getInitTasks() {
      // 预加载 上下的定期任务
      function preloadFn(that) {
        const detailId = tasks.value.findIndex(task => task.detailId);
        const arr = [];
        tasks.value.forEach(task => {
          if (task.detailId) {
            arr.push(task);
          }
        });
        if (detailId !== -1) {
          // 只要有1个真实的任务 就预加载上下周期的任务
          const { pageCount } = uni.$task;
          nextTick(() => {
            // 向上拿数据
            getTasks({ timeNode: +tasks.value[detailId].planStart, queryType: 0, queryNum: pageCount });
            // 向下拿数据
            const nextQueryTime = +uni.$time.add(+arr[arr.length - 1].planStart, 1, timeGranularity.value);
            getTasks({ timeNode: nextQueryTime, queryType: 1, queryNum: pageCount });
          });
        } else {
          // 没有任务 上下显示时间刻度
          // 向上加载
          setPrevPlaceholderTasks();
          // // 向下加载
          setNextPlaceholderTasks();
        }
      }
      // 根据时间基准点和角色查找定期任务
      getTasks({ queryType: 0 }); // 向上获取定期任务数据

      // 根据项目id获取角色列表
      getTasks({ queryType: 1 }, preloadFn); // 向下获取定期任务数据
    }

    /**
     * 根据时间基准点和角色查找定期任务
     * @param {object} query
     * @param {string} query.roleId 角色id
     * @param {string} query.timeNode 时间基准点 默认当前
     * @param {string} query.timeUnit 时间颗粒度 默认天
     * @param {string} query.queryNum 查找颗粒度数量 默认3个
     * @param {number} query.queryType 0向上查找 1向下查找(默认) 下查包含自己，上查不包含
     */
    function getTasks(query, fn) {
      store.commit('task/setShowSkeleton', false);
      const params = generateGetTaskParam(query);
      uni.$catchReq.getRegularTask(params, (err, data) => {
        store.commit('task/setShowSkeleton', false);
        if (err) {
          // TODO: 提示错误
          console.error('err: ', err);
        } else {
          store.commit('task/setShowScrollTo', true);
          // 有数据用数据替换刻度
          // 没有数据 继续加载刻度
          if (data && data.length) {
            replacePrevData(data, params.queryType);
            params.queryType === 0 ? store.commit('task/setTopEnd', false) : store.commit('task/setBottomEnd', false);
          } else {
            // TODO: 0 -> 向上  1 -> 向下
            params.queryType === 0 ? setPrevPlaceholderTasks() : setNextPlaceholderTasks();
          }
          if (tasks.value.length && fn) {
            fn(this);
          }
        }
      });
    }

    /**
     * 生成getTasks所用的参数
     * @param {object} query getTasks传递的参数
     */
    function generateGetTaskParam(query) {
      return {
        roleId: roleId.value,
        timeNode: query.timeNode || timeNode.value,
        timeUnit: query.timeUnit || timeUnit.value,
        queryNum: query.queryNum || 3,
        queryType: query.queryType,
        projectId: projectId.value,
      };
    }

    // 设置时间轴向上的空数据
    function setPrevPlaceholderTasks() {
      store.commit('task/setTopEnd', true);
      let startTime = '';
      if (!tasks.value || !tasks.value.length) {
        startTime = Date.now(); // 没有任务就应该是时间基准点
      } else {
        startTime = tasks[0].planStart - 0; // 有任务就是第一个任务的计划开始时间
      }
      const placeholderTasks = uni.$task.setPlaceholderTasks(startTime, true, timeGranularity.value);
      store.commit('task/setUpTasks', placeholderTasks);
    }

    // 设置时间轴向下的空数据
    function setNextPlaceholderTasks() {
      store.commit('task/setBottomEnd', true);
      let startTime = '';
      if (!tasks.value || !tasks.value.length) {
        startTime = Date.now();
      } else {
        startTime = +tasks.value[tasks.value.length - 1].planStart;
      }
      const initData = uni.$task.setPlaceholderTasks(startTime, false, timeGranularity.value);
      store.commit('task/setDownTasks', initData);
    }

    /**
     * 用拿到的新数据 替换 时间刻度/旧数据
     * 先对比 新旧数据的 始末时间 补齐刻度
     * 再遍历对比 用任务替换刻度
     * @param {array} data 服务端返回的新数据 上边已经处理过空值
     * @param {number} type 0 -> 向上 1->向下
     */
    function replacePrevData(data, type) {
      let oldTasks = fillPlaceholderTask({ tasks.value, data, timeGranularity.value }); // 已经上下补齐时间刻度的

      // 遍历对比 用任务替换刻度
      // TODO: tasks越来越多  遍历越来越多 需要优化
      oldTasks.forEach((taskItem, index) => {
        const arr = data.filter(dataItem => dayjs(+dataItem.planStart).isSame(+taskItem.planStart, timeGranularity.value));
        if (arr && arr.length) {
          oldTasks.splice(index, 1, [...arr]); // 这里加入的数据是array类型的, [{},{},[],[],{}]
        }
      });

      oldTasks = flatten(oldTasks); // 1维拍平

      store.commit('task/clearTasks');
      type === 0 ? store.commit('task/setUpTasks', oldTasks) : store.commit('task/setDownTasks', oldTasks);
    }

    /**
     * 超出旧数据上、下限 补齐时间刻度到新数据的起始时间颗粒度
     */
    function fillPlaceholderTask({ tasks, data, timeGranularity }) {
      const { prev, next } = uni.$task.computeFillPlaceholderTaskCount({ tasks, data, timeGranularity });
      if (prev) {
        const newTasks = uni.$task.setPlaceholderTasks(+tasks[0].planStart, true, timeGranularity, prev);
        store.commit('task/setUpTasks', newTasks);
      }
      if (next) {
        const newTasks = uni.$task.setPlaceholderTasks(+tasks[tasks.length - 1].planStart, false, timeGranularity, next);
        store.commit('task/setDownTasks', newTasks);
      }
      return tasks.value;
    }

    /**
     * 初始化
     * @param {object | null} options
     */
    function init(options) {
      if (!token.value) {
        // 不论有没有token都直接从userId获取token
        // token有过期时间 从本地获取可能是过期 干脆直接从userId获取
        if (!options || !options.u) {
          uni.$ui.showToast('缺少用户信息参数'); // 参数里没有u (userId)提示
        } else {
          store.dispatch('user/getToken', options.u);
        }
      }

      // 参数里有项目名称  就设置标题里的项目名称
      options && options.pname && store.commit('project/setProjectName', options.pname);

      if (!options || !options.p) {
        uni.$ui.showToast('缺少项目信息参数'); // 没有项目id参数
      } else {
        if (options.p !== uni.$storage.getStorageSync('projectId')) {
          console.log('切项目了');
          uni.$storage.setStorageSync('roleId', '');
        }
        // TODO
        getProjectById({ projectId: options.p, num: 0 }); // 根据项目id获取项目信息
        // 查询医院是否填写了调查问卷
        // this.handleQueryNotWrite(options.p);
        // 根据项目id获取成员列表
        store.dispatch('role/getAllMembers', { projectId: options.p });
      }
    }

    // 分享链接来的初始化
    async function shareInit(options) {
      const storageUser = uni.$storage.getStorageSync('user');
      const user = storageUser ? JSON.parse(storageUser) : null;
      if (user && user.id) {
        await store.dispatch('user/getToken', user.id);
        const res = await clickShare({ code: options.shareId });
        if (res && res.projectId) {
          let query = { ...uni.$route.query };
          query = {
            u: user.id,
            p: res.projectId,
          };
          uni.$router.push({ path: uni.$route.path, query });
          init(query);
        }
      } else {
        uni.$ui.showToast('缺少用户信息参数,请登录');
      }
    }

    function setOptions(options) {
      if (options.share && options.share === '1') {
        shareInit(options);
      } else {
        init(options);
      }
    }
    setOptions(options);

    /**
     * 点击分享连接
     * @param {any} commit
     * @param {object} param 请求参数
     */
    async function clickShare(param) {
      try {
        const data = await uni.$catchReq.clickShare(param);
        return data;
      } catch (error) {
        uni.$ui.showToast(error.msg || '获取失败');
      }
    }

    /**
     * 通过项目id获取项目信息
     * @param {object} params 提交的参数
     */
    async function getProjectById(params) {
      try {
        const data = await uni.$u.api.findProjectById(params);
        store.commit('project/setProject', data);
        // 根据项目id获取角色列表
        getRoles(params);
      } catch (error) {
        console.log('error: ', error || '获取项目信息失败');
      }
    }

    /**
     * 通过项目id获取角色信息
     * @param {string} projectId
     * @param {object} params 提交的参数
     */
    function getRoles(params) {
      uni.$catchReq.findShowRole(params, (err, data) => {
        if (err) {
          console.error('err: ', err || '获取角色信息失败');
        } else {
          store.commit('role/setInvisibleRoles', data ? data.invisibleList : []);
          store.commit('role/setVisibleRoles', data ? data.visibleList : []);
          setInitialRoleId(data ? data.visibleList : []);
        }
      });
    }

    // 设置 初始显示角色信息
    function setInitialRoleId(visibleList) {
      if (!visibleList || !visibleList.length) return;
      const index = visibleList.findIndex(item => +item.mine === 1);
      const currentRole = index > 0 ? visibleList[index] : visibleList[0];
      const storageRoleId = uni.$storage.getStorageSync('roleId');
      const currentRoleId = storageRoleId || (currentRole ? currentRole.id : '');
      store.commit('role/setRoleId', currentRoleId);
      // 清空storage
      uni.$storage.setStorageSync('roleId', '');
    }

    // 获取可变全局任务
    function getGlobalData() {
      const param = { roleId: roleId.value, timeNode: timeNode.value, timeUnit: timeUnit.value, projectId: projectId.value };
      store.dispatch('task/getGlobal', param);
    }

    // 清除已有的任务数据
    function clearTasksData() {
      // 清空日常任务的数据
      store.commit('task/setPermanents', []);
      store.commit('task/setDailyTasks', []);
      // 清空定期任务数据
      store.commit('task/clearTasks');
      // 到顶的标志复位
      // 到底的标志复位
      store.commit('task/clearEndFlag');
    }
    return {
      height,
      timeLine,
      roleId,
      timeNode,
      timeUnit,
      tasks,
      newProjectInfo,
      showScrollTo,
      timeGranularity,
      projectId,
      userId,
      initPlanTasks,
      getInitTasks,
      getTasks,
      generateGetTaskParam,
      setPrevPlaceholderTasks,
      setNextPlaceholderTasks,
      replacePrevData,
      fillPlaceholderTask,
      init,
      shareInit,
      setOptions,
      clickShare,
      getProjectById,
      getRoles,
      setInitialRoleId,
      getGlobalData,
      clearTasksData,
    };
  },
});
</script>

<style lang="scss" scoped>
.border-b {
  border-bottom: 1px solid #e4e7ed;
}
</style>
