import Vue from 'vue';

const request = uni.$u.http;
const noMoreStatus = 'nomore';
const get = request.get.bind(request);

const createList = (config = {}) => ({
  requesting: false,
  status: 'loading',
  page: 0,
  data: [],
  ...config,
});

const getStatus = (res) => {
  const { has_next: hasNext, total_count: total } = res;
  return total === 0 ? 'empty' : hasNext ? 'loading' : noMoreStatus;
};

const getList = async (context, listKey = '', req = [], options = {}) => {
  const { transform = (data) => data, mergeData, abandon = () => false, beforeSetData = () => {}, callback = () => {} } = options;

  const getTarget = () => context[listKey];
  const list = getTarget();

  const setList = (value) => Vue.set(context, listKey, value);
  const setKey = (key, value) => Vue.set(getTarget(), key, value);

  if (list.requesting || list.status === noMoreStatus) return;

  setKey('requesting', true);
  const newPage = list.page + 1;

  try {
    let res;
    if (req instanceof Promise) {
      res = await req;
    } else {
      const [url, data, ...restParams] = Array.isArray(req) ? req : [req];
      const params = { page: newPage, page_num: newPage, ...data };
      res = await get(url, { params }, ...restParams);
    }
    if (abandon()) return;
    const newListData = transform(res.list);
    const newList = {
      ...list,
      total: res.total_count,
      status: getStatus(res),
      page: newPage,
      data: mergeData ? mergeData(list.data, newListData) : newPage === 1 ? newListData : [...list.data, ...newListData],
    };
    beforeSetData();
    setList(newList);
    return Promise.resolve(res);
  } catch (e) {
    console.error('getList:', e);
    setList({ ...list, status: 'error' });
  } finally {
    setKey('requesting', false);
  }
};

export { createList, getList };
