import request from "@/utils/request";
import { PageOption } from "@smallwei/avue";
import { ElMessage, ElMessageBox } from "element-plus";
import { useUserStoreHook } from "@/store/modules/user";

interface UseCrudConfig {
  // 模块的url，用来进行增删改查
  src?: string;

  dataListUrl?: string;

  // 需要操作的数据
  row?: any;
  // done用于结束操作
  done?: () => void;
  // 具体操作的行
  index?: number;
  // 用于中断操作
  loading?: () => void;
  // 额外查询参数 一般用search的值就可以了
  params?: object;
  // 是否是编辑，如果是编辑调用更新，否则调用新增
  isEdit?: boolean;
  //   用于多选选中后添加进入，toDeleteIds中的key值。
  multipleSelectKey?: string;
  // todo 这个值是什么
  pageStr?: string;
}

export const useCrud = (config?: UseCrudConfig) => {
  const url = ref(config?.src);
  const pageStr = ref(config?.pageStr ? config?.pageStr : "yes");
  const commonConfig = ref(config);
  /** 表格配置属性 */
  const option = ref({
    searchIcon: true,
    // searchSpan: 4,
    searchIndex: 3, //searchIcon是否启用功能按钮, searchIndex配置收缩展示的个数,默认为2个
    index: true, //是否显示第几项
    indexLabel: "序号",
    indexWidth: "55px",
    refreshBtn: false,
    border: true,
    viewBtn: true,
    tip: false, //选中的提示
  });
  const data = ref<any>([]); //表格数据
  const lines = ref<any>([]); //产线
  const form = ref({}); //新增或者编辑弹出的表单绑定值
  /** 表格顶部搜索的表单的变量 v-model */
  const search = ref({});

  /** 表格的分页数据 v-model */
  const page = ref<PageOption>({
    total: 0,
    currentPage: 1,
    pageSize: 10,
  });
  /** 配置项结构 v-model */
  // defaults ?: AvueCrudDefaults;
  // 多选返回的数组，命名是因为后来增加了很多功能，现在这个数组里面的值是根据multipleSelectKey来决定
  const toDeleteIds = ref<Array<string>>([]);
  // 多选返回的数组,返回每一行的row数据
  const selectedRows = ref<any[]>([]);
  const save = async (config?: UseCrudConfig) => {
    try {
      const path = config?.isEdit ? "/update" : "/add";

      const res = (await request({
        url: `${url.value}${path}`,
        method: "post",
        data: form.value,
      })) as any;
      if (res?.code == 200) {
        Methords.dataList();
        config?.done && config?.done();
        ElMessage.success(res?.msg ?? "");
      } else {
        config?.loading && config?.loading();
        ElMessage.error(res?.msg ?? "");
      }
    } catch (err) {
      config?.loading && config?.loading();
    }
  };

  const handleSearchData = () => {
    // const array = [null, undefined, ""];
    search.value = Object.fromEntries(
      Object.entries(search.value).filter(
        ([key, value]) =>
          value !== null &&
          value !== undefined &&
          Object.keys(value).length !== 0
      )
    );
  };

  /**
   * 表格增删改查等基本方法
   */
  const Methords = {
    /**
     * 查询方法
     */
    dataList: async (config?: UseCrudConfig) => {
      handleSearchData();
      try {
        const res = await request({
          url:
            pageStr.value == "no"
              ? commonConfig.value?.dataListUrl ?? `${url.value}`
              : commonConfig.value?.dataListUrl ?? `${url.value}/page`,
          method: "post",
          data: {
            pageNo: page.value.currentPage,
            pageSize: page.value.pageSize,
            ...search.value,
            ...(commonConfig.value?.params ?? {}),
          },
        });
        if (res?.data) {
          if (res?.data instanceof Array) {
            data.value = res?.data || [];
            page.value.total = res?.data?.length || 0;
          } else {
            data.value = res?.data?.records || [];
            lines.value = res?.data?.productLines || [];
            page.value.total = res?.data?.totalCount || 0;
          }
        }
        config?.done && config?.done();
      } catch (err) {
        config?.loading && config?.loading();
      } finally {
        config?.done && config?.done();
      }
    },
    dataEditList: async (config?: UseCrudConfig) => {
      handleSearchData();
      try {
        const res = await request({
          url: pageStr.value == "no" ? `${url.value}` : `${url.value}/page`,
          method: "post",
          data: {
            pageNo: page.value.currentPage,
            pageSize: page.value.pageSize,
            ...search.value,
            ...(commonConfig.value?.params ?? {}),
          },
        });
        if (res?.data) {
          if (res?.data instanceof Array) {
            data.value = res?.data || [];
            page.value.total = res?.data?.length || 0;
          } else {
            data.value = res?.data?.records || [];
            for (let i = 0; i < data.value.length; i++) {
              data.value[i].$cellEdit = true;
              if (
                data.value[i].children != undefined &&
                data.value[i].children != null &&
                data.value[i].children.length > 0
              ) {
                for (let j = 0; j < data.value[i].children.length; j++) {
                  data.value[i].children[j].$cellEdit = true;
                }
              }
            }
            page.value.total = res?.data?.totalCount || 0;
          }
        }
        config?.done && config?.done();
      } catch (err) {
        config?.loading && config?.loading();
      } finally {
        config?.done && config?.done();
      }
    },
    dataNoPageList: async (config?: UseCrudConfig) => {
      handleSearchData();
      try {
        const res = await request({
          url: `${url.value}/list`,
          method: "post",
          data: {
            ...search.value,
          },
        });

        if (res?.data) {
          data.value = res?.data || [];
        }
        config?.done && config?.done();
      } catch (err) {
        config?.loading && config?.loading();
      } finally {
        config?.done && config?.done();
      }
    },
    createRow: (row: any, done: () => void, loading: () => void) => {
      save({ row: row, done: done, loading: loading });
    },

    updateRow: (
      row: any,
      index: number,
      done: () => void,
      loading: () => void
    ) => {
      save({
        row: row,
        done: done,
        loading: loading,
        index: index,
        isEdit: true,
      });
    },

    deleteRow: async (row: any, index: number, done: () => void) => {
      ElMessageBox.confirm("是否删除所选中数据？", "提示", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning",
      }).then(async () => {
        if (row.children && row.children.length > 0) {
          ElMessage.error("请先解绑下级关系");
          return;
        }
        try {
          const res = await request({
            url: `${url.value}/del`,
            method: "post",
            data: row,
          });
          Methords.dataList();
          config?.done && config?.done();
        } catch (err) {
          config?.loading && config?.loading();
        } finally {
          config?.done && config?.done();
        }
      });
    },

    // 设置selection: true,后监听选中改变事件，将Id存入数组
    selectionChange: (rows?: any[]) => {
      toDeleteIds.value = [];
      selectedRows.value = [];
      rows?.forEach((element) => {
        toDeleteIds.value.push(
          element[commonConfig.value?.multipleSelectKey ?? "id"]
        );
        selectedRows.value.push(element);
      });
    },

    /**
     * 表格上方的多选删除方法
     */
    multipleDelete: async () => {
      ElMessageBox.confirm("是否删除所选中数据？", "提示", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning",
      }).then(async () => {
        try {
          const res = await request({
            url: `${url.value}/batch-del`,
            method: "post",
            data: { ids: toDeleteIds.value },
          });
          Methords.dataList();
          config?.done && config?.done();
        } catch (err) {
          config?.loading && config?.loading();
        } finally {
          config?.done && config?.done();
        }
      });
    },

    /**
     *  表格拖拽后批量保存
     * */
    multipleUpdate: async () => {
      try {
        // 由于数据带有$开头的属性，所以需要处理下，改为只传id和sortNum。
        const dtosArray: { id: string; sortNum: number }[] = [];
        for (let i = 0; i < data.value.length; i++) {
          let cur = page.value.currentPage ?? 1;
          cur = cur - 1;
          const size = page.value.pageSize ?? 10;
          let sortNum = cur * size;
          sortNum = sortNum + i;

          dtosArray.push({ id: data.value[i].id, sortNum: sortNum });
        }
        const res = await request({
          url: `${url.value}/batch-update`,
          method: "post",
          data: dtosArray,
        });
        Methords.dataList();
        config?.done && config?.done();
      } catch (err) {
        config?.loading && config?.loading();
      } finally {
        config?.done && config?.done();
      }
    },
    /**
     * 点击搜索按钮触发
     */
    searchChange: async (params: any, done: () => void) => {
      // 点击搜索的时候重置search的值，要不然会传过去所有的值包括空字符串的值
      search.value = params;
      page.value.currentPage = 1;
      Methords.dataList({ done: done });
    },

    /**
     * 点击清空按钮触发
     */
    resetChange: async (item: any) => {
      page.value.currentPage = 1;
      Methords.dataList();
    },
  };

  /**
   * 表格辅助方法，按钮权限，导入导出
   */
  const Utils = {
    checkBtnPerm: (str: string) => {
      // 「超级管理员」拥有所有的按钮权限
      const { roles, perms } = useUserStoreHook().user;
      if (roles.includes("ROOT")) {
        return true;
      }
      const hasPerm = perms?.some((perm) => {
        return str.includes(perm);
      });
      return hasPerm;
    },

    /**
     * 根据返回的数据下载文件
     */
    downloadFile: (response: any) => {
      const fileData = response.data;
      const fileName = decodeURI(
        response.headers["content-disposition"].split(";")[1].split("=")[1]
      );
      const fileType =
        "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8";
      const blob = new Blob([fileData], { type: fileType });
      const downloadUrl = window.URL.createObjectURL(blob);
      const downloadLink = document.createElement("a");
      downloadLink.href = downloadUrl;
      downloadLink.download = fileName;
      document.body.appendChild(downloadLink);
      downloadLink.click();
      document.body.removeChild(downloadLink);
      window.URL.revokeObjectURL(downloadUrl);
    },

    /**
     * 下载模版 传入url
     */
    downloadTemplate: async (urlStr: string) => {
      const response = await request({
        url: urlStr,
        method: "get",
        responseType: "arraybuffer",
      });
      Utils.downloadFile(response);
    },

    /**
     * 根据搜索项导出数据
     */
    exportData: async (urlStr: string) => {
      handleSearchData();
      const response = await request({
        url: urlStr,
        method: "post",
        data: search.value,
        responseType: "arraybuffer",
      });
      Utils.downloadFile(response);
    },
  };

  return {
    url,
    option,
    data,
    lines,
    form,
    search,
    page,
    toDeleteIds,
    selectedRows,
    Methords,
    Utils,
    commonConfig,
  };
};
