import {
  ref,
  watch,
  onActivated,
  onMounted,
  reactive,
  isReactive,
  Ref,
  nextTick,
} from "vue";
import { UN_REQ_NUM } from "@/constant/sys";
import { dateFormat, mix, throttle } from "@/util";
import { ElMessage } from "element-plus";
import { confirm } from "@/helper/message";
import { PaggingReq, PaggingRes } from "@/request";

// 构建数据源列表操作
const genTableOperate = <T>() => {
  const tableState = ref({
    rows: [] as T[],
    selectRows: [] as T[],
  });
  return {
    tableState,
    changeSelectRows(selected: T[]) {
      tableState.value.selectRows = selected as any;
    },
  };
};

// 构建分页配置状态
const genPagOperate = () => {
  const pagStore = ref({
    currentPage: 1,
    size: 12,
    total: 0,
  });

  return {
    pagStore,
    sizeChange(size: number) {
      pagStore.value.size = size;
    },
    currentChange(page: number) {
      pagStore.value.currentPage = page;
    },
  };
};

// 搜索状态操作
const genQueryOperate = <Q>(paramsTemlate?: Q) => {
  const paramsStore = ref(paramsTemlate && { ...paramsTemlate }) as Ref<Q>;
  return {
    paramsStore,
    reset() {
      if (paramsTemlate) {
        mix(paramsStore.value, true, paramsTemlate);
      }
    },
  };
};

type Operate<P, RAW, NRAW> = {
  get: (param: PaggingReq<P>) => Promise<PaggingRes<RAW>> | PaggingRes<RAW>;
  set?: (param: RAW) => void;
  add?: (param: NRAW) => void;
  del?: (param: RAW) => void;
  mapper?: { delMsg?: string };
};

type PaggingProps<P, RAW, NRAW> = Operate<P, RAW, NRAW> & {
  rowKey?: keyof RAW;
  itemTemplate?: Partial<RAW | NRAW>;
  paramsTemlate?: P;
};

export const usePagging = <PARAM, RAW, NRAW>(
  props: PaggingProps<PARAM, RAW, NRAW>
) => {
  const tableOperate = genTableOperate<RAW>();
  const pagOperate = genPagOperate();
  const queryOperate = genQueryOperate(props.paramsTemlate);
  const loading = ref(false);
  const refreshRaw = async () => {
    loading.value = true;
    const pag = pagOperate.pagStore.value;
    const paramsRaw = {
      ...queryOperate.paramsStore.value,
      pageNum: pag.currentPage,
      pageSize: pag.size,
    } as any;
    const params: any = Object.keys(paramsRaw)
      .filter((key) => ![UN_REQ_NUM, "" + UN_REQ_NUM].includes(paramsRaw[key]))
      .reduce((t, k) => {
        t[k] = paramsRaw[k];
        if (t[k] instanceof Date) {
          t[k] = dateFormat(t[k], "yyyy-MM-dd");
        }
        return t;
      }, {} as any);
      console.log('queryOperate', queryOperate, paramsRaw, params);
    const data = await props.get(params);
    pag.total = data.total;
    tableOperate.tableState.value.rows = data.list as any;
    console.log('await', tableOperate.tableState.value);
    await nextTick();
    loading.value = false;
  };

  const refresh = throttle(refreshRaw, 300);
  const itemAPI = {
    async set(data: RAW) {
      if (props.set) {
        await props.set(data);
        await refresh();
      }
    },
    async add(data: NRAW) {
      if (props.add) {
        await props.add(data);
        await refresh();
      }
    },
    async del(data: RAW) {
      if (props.del) {
        await props.del(data);
        await refresh();
      }
    },
  };

  watch(
    () => [queryOperate?.paramsStore, ...(isReactive(props) ? [props] : [])],
    refresh,
    { deep: true }
  );

  onActivated(refresh);
  onMounted(refresh);

  const state = reactive({
    pag: pagOperate.pagStore!,
    table: tableOperate.tableState!,
    query: queryOperate.paramsStore!,
  });

  return {
    async del(data: RAW) {
      if (await confirm(props.mapper?.delMsg || "确定要删除此数据吗？")) {
        const result = await itemAPI.del!(data);
        ElMessage.success("删除成功");
        return result;
      }
    },
    async deleteSelected() {
      const rows = tableOperate.tableState.value.selectRows;
      if (rows.length === 0) {
        ElMessage.error("请勾选数据后再删除数据！");
      } else if (
        await confirm(
          props.mapper?.delMsg || `确定要删除这${rows.length}条数据吗？`
        )
      ) {
        await Promise.all(rows.map((item) => itemAPI?.del!(item as any)));
        ElMessage.success("删除成功");
        refresh();
      }
    },
    changPageCurrent: (data: number) => {
      pagOperate.currentChange(data);
      refresh();
    },
    changPageSize: (data: number) => {
      pagOperate.sizeChange(data);
      refresh();
    },
    state,
    loading,
    add: itemAPI.add,
    set: itemAPI.set,
    changeSelectRows: tableOperate.changeSelectRows,
    refresh,
    queryReset: queryOperate.reset,
  };
};
