import { copyTextToClipboard } from "@pureadmin/utils";
import { message } from "@/utils/message";
import moment from "moment";
import { request } from "@/utils";

import { ref } from "vue";

export function validateForm(formRef) {
  return new Promise((resolve, reject) => {
    formRef &&
      formRef.validate(valid => {
        if (valid) {
          resolve(true);
        } else {
          resolve(false);
        }
      });
  });
}
export function limitConcurrency(promises, callback, concurrency = 2) {
  let runningPromises = 0;
  let completedPromises = 0;
  const n = promises.length;

  function runNextPromise() {
    while (
      runningPromises < concurrency &&
      completedPromises + runningPromises < n
    ) {
      const promise = promises[completedPromises + runningPromises];
      runningPromises++;

      promise()
        .then(() => {
          completedPromises++;
          runningPromises--;
          if (completedPromises === n) {
            callback();
          } else {
            runNextPromise();
          }
        })
        .catch(error => {
          console.error(error);
          completedPromises++;
          runningPromises--;
          runNextPromise();
        });
    }
  }

  runNextPromise();
}
export function randomString(len = 32) {
  const $chars = "ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz0123456789";
  const maxPos = $chars.length;
  let pwd = "";
  for (let i = 0; i < len; i++) {
    pwd += $chars.charAt(Math.floor(Math.random() * maxPos));
  }
  return pwd;
}

export const debounce = (fn: Function, delay: number) => {
  let timeout: any = undefined;

  return (...args: any[]) => {
    if (timeout) {
      clearTimeout(timeout);
    }

    timeout = setTimeout(() => {
      fn(...args);
    }, delay);
  };
};
export function throttle(fn: Function, time: number) {
  //初始化时间
  let lastTime = 0;
  return function () {
    //记录当前函数触发时间
    const nowTime = Date.now();
    if (nowTime - lastTime > time) {
      fn.call(this);
      lastTime = nowTime;
    }
  };
}

export const handleCopy = async copyValue => {
  const success = copyTextToClipboard(copyValue);
  // success
  //   ? message("复制成功", { type: "success" })
  //   : message("复制失败", { type: "error" });
};

export const parseJsonData = (data, defaultValue = "") => {
  try {
    return data
      ? typeof data == "string"
        ? JSON.parse(data)
        : data
      : defaultValue;
  } catch (e) {
    console.log(e);
    return defaultValue;
  }
};

// copy的 校验非空有0
export function empty(v) {
  switch (typeof v) {
    case "undefined":
      return true;
    case "string":
      return !v;
    case "boolean":
      if (!v) return true;
      break;
    case "number":
      return false;
    case "object":
      if (null === v) return true;
      if (undefined !== v.length && v.length == 0) return true;
      for (const k in v) {
        return false;
      }
      return true;
      break;
  }
  return false;
}

export const getInterval = (startDate: string, endDate: string) => {
  const ms = new Date(endDate).getTime() - new Date(startDate).getTime();
  if (ms < 0) return 0;
  return Math.floor(ms / 1000 / 60 / 60) * 60;
};

export function deepClone<T>(obj: T): T {
  const isObject = (input: any): input is { [key: string]: any } => {
    return input !== null && typeof input === "object";
  };

  if (!isObject(obj)) {
    return obj;
  }

  if (Array.isArray(obj)) {
    return obj.map(item => deepClone(item)) as unknown as T;
  }

  const clonedObj: { [key: string]: any } = {};

  for (const key in obj) {
    if (Object.prototype.hasOwnProperty.call(obj, key)) {
      clonedObj[key] = deepClone(obj[key]);
    }
  }

  return clonedObj as T;
}

export function parseJSON(input: any, catchVal?: any): any {
  if (!input) return input;
  try {
    const parsed = JSON.parse(input);
    return parsed;
  } catch (error) {
    console.log(error);
    return catchVal != undefined ? catchVal : input;
  }
}

export const formatAge = (birthday: string) => {
  if (!birthday) return "";
  if (!isNaN(Number(birthday))) return birthday;
  let time = birthday.replace(/-/g, "/");
  const timeFormLen = time.includes("/") && time.split("/").length;
  if (timeFormLen < 3) {
    for (let i = 0; i < timeFormLen - 1; i++) {
      time += "/01";
    }
  }
  const offset = Date.now() - +new Date(time);
  return parseInt(String(offset / 86400000 / 365));
};

export function msToDate(ms: any, type = "dateTime") {
  const dateTime = new Date(ms);
  const year = dateTime.getFullYear();
  const month = dateTime.getMonth();
  const date = dateTime.getDate();
  const hour = dateTime.getHours();
  const minute = dateTime.getMinutes();
  const second = dateTime.getSeconds();

  const resultDateTime =
    year +
    "-" +
    (month + 1 >= 10 ? month + 1 : "0" + (month + 1)) +
    "-" +
    (date + 1 <= 10 ? "0" + date : date) +
    " " +
    (hour + 1 <= 10 ? "0" + hour : hour) +
    ":" +
    (minute + 1 <= 10 ? "0" + minute : minute) +
    ":" +
    (second + 1 <= 10 ? "0" + second : second);
  const resultDate =
    year +
    "-" +
    (month + 1 >= 10 ? month + 1 : "0" + (month + 1)) +
    "-" +
    (date + 1 <= 10 ? "0" + date : date);
  switch (type) {
    case "year":
      return year.toString();
    case "year-month":
      return `${year}-${month + 1 >= 10 ? month + 1 : "0" + (month + 1)}`;
    case "dateTime":
      return resultDateTime;
    default:
      return resultDate;
  }
}

export function downloadReportRename(downloadUrl, filename) {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();
    xhr.open("GET", downloadUrl, true);
    xhr.responseType = "blob";
    xhr.onload = () => {
      if (xhr.status === 200) {
        const link = document.createElement("a");
        const body = document.body;
        const blob = xhr.response;
        link.href = window.URL.createObjectURL(blob);
        link.download = filename;

        // hide the link
        link.style.display = "none";
        body.appendChild(link);

        link.click();
        body.removeChild(link);

        window.URL.revokeObjectURL(link.href);
        resolve(link.href);
      } else {
        reject(new Error(`Request failed with status ${xhr.status}`));
      }
    };
    xhr.onerror = () => {
      reject(new Error("Request failed"));
    };
    xhr.send();
  });
}
export const deduplicateArrayByKeys = (arr, keys) => {
  const seen = new Set(); // 用于存储已经出现过的键值组合
  return arr.filter(item => {
    const itemKeys = keys.map(key => item[key]).join("-");
    if (!seen.has(itemKeys)) {
      seen.add(itemKeys);
      return true; // 如果键值组合不重复，则保留该项
    }
    return false; // 如果键值组合重复，则过滤掉该项
  });
};

export const previewTime = (type = 0, value) => {
  // 0:每天；1:每周；2:每月；3:固定多少天后
  if (!value)
    return {
      label: "-"
    };
  const count = Number(value);
  const now = moment().format("YYYY-MM-DD");

  if (type == 0) {
    const day = moment()
      .day(moment().day() + count)
      .format("YYYY-MM-DD");
    return {
      label: `${now} 至 ${day}`,
      startTime: now,
      endTime: day
    };
  }
  if (type == 1) {
    const day = moment()
      .day(moment().day() + count * 7)
      .format("YYYY-MM-DD");
    return {
      label: `${now} 至 ${day}`,
      startTime: now,
      endTime: day
    };
  }
  if (type == 2) {
    let month = "";
    month = moment()
      .month(moment().month() + count)
      .format("YYYY-MM");

    return {
      label: `${moment().format("YYYY-MM")}月 至 ${month}月`,
      startTime: now,
      endTime: moment()
        .month(moment().month() + count)
        .endOf("month")
        .format("YYYY-MM-DD")
    };
  }

  if (type == 3) {
    const day = moment()
      .day(moment().day() + count)
      .format("YYYY-MM-DD");
    return {
      label: `${day}`,
      startTime: now,
      endTime: day
    };
  }
};

export const transformDataExpand = (data, key) => {
  if (!key) return data;
  const transformedData = [];
  console.log(data);

  data?.forEach(item => {
    transformedData.push(item);
    if (item[key]?.length) {
      item[key].forEach((v, index) => {
        transformedData.push(v);
      });
    }
  });
  return transformedData;
};
export const timeDiffer = time => {
  return moment(time).diff(moment().format("YYYY-MM-DD"), "day");
};
export function findScope(string) {
  const scopes = [
    {
      id: 12,
      name: "<=B"
    },
    {
      id: 11,
      name: ">=A"
    },
    {
      id: 10,
      name: "-A~B"
    },
    {
      id: 9,
      name: "-A-B"
    },
    {
      id: 8,
      name: "A~"
    },
    {
      id: 7,
      name: "A~B"
    },
    {
      id: 6,
      name: "<B"
    },
    {
      id: 5,
      name: ">A"
    },
    {
      id: 4,
      name: "A-B"
    },
    {
      id: 3,
      name: "A--B"
    },
    {
      id: 2,
      name: "≥A"
    },
    {
      id: 1,
      name: "≤B"
    }
  ];
  const defaultScope = { origin: string, start: null, end: null };
  for (const scope of scopes) {
    const name = scope.name;
    if (name.includes("-A") && name.includes("B")) {
      const pattern = new RegExp(
        name.replace(/A/g, "(\\d+(\\.\\d+)?)").replace(/B/g, "(\\d+(\\.\\d+)?)")
      );
      const matchObj = string.match(pattern);
      if (matchObj) {
        defaultScope.start = -parseFloat(matchObj[1]).toFixed(4);
        defaultScope.end = parseFloat(matchObj[3]).toFixed(4);
        return defaultScope;
      }
    } else if (name.includes("A") && name.includes("B")) {
      const pattern = new RegExp(
        name.replace(/A/g, "(\\d+(\\.\\d+)?)").replace(/B/g, "(\\d+(\\.\\d+)?)")
      );
      const matchObj = string.match(pattern);
      if (matchObj) {
        defaultScope.start = parseFloat(matchObj[1]).toFixed(4);
        defaultScope.end = parseFloat(matchObj[3]).toFixed(4);
        return defaultScope;
      }
    } else if (name.includes("A")) {
      const pattern = new RegExp(name.replace(/A/g, "(\\d+(\\.\\d+)?)"));
      const matchObj = string.match(pattern);
      if (matchObj) {
        defaultScope.start = parseFloat(matchObj[1]).toFixed(4);
        defaultScope.end = "9999.9999";
        return defaultScope;
      }
    } else if (name.includes("B")) {
      const pattern = new RegExp(name.replace(/B/g, "(\\d+(\\.\\d+)?)"));
      const matchObj = string.match(pattern);
      if (matchObj) {
        defaultScope.start = "0.0000";
        defaultScope.end = parseFloat(matchObj[1]).toFixed(4);
        return defaultScope;
      }
    }
  }
  return null;
}
export const getWeek = date => {
  // 时间戳
  const week = moment(date).day();
  switch (week) {
    case 1:
      return "周一";
    case 2:
      return "周二";
    case 3:
      return "周三";
    case 4:
      return "周四";
    case 5:
      return "周五";
    case 6:
      return "周六";
    case 0:
      return "周日";
  }
};

export const sleep = time => new Promise(resolve => setTimeout(resolve, time));

export function groupArray(arr: [], size: number) {
  const groups = [];
  let groupIndex = 0;
  for (let i = 0; i < arr.length; i++) {
    if (i % size === 0) {
      groups[groupIndex] = [];
      groupIndex++;
    }
    groups[groupIndex - 1].push(arr[i]);
  }
  return groups;
}

export const scrollUp = (tableRef, timer = 100) => {
  const demo =
    tableRef.$refs.bodyWrapper.getElementsByClassName("el-scrollbar__wrap")[0];
  const tableScroll = ref(true);
  demo.addEventListener("mouseover", () => {
    tableScroll.value = false;
  });
  demo.addEventListener("mouseout", () => {
    tableScroll.value = true;
  });
  setInterval(() => {
    if (tableScroll.value) {
      demo.scrollTop += 1;
      if (demo.clientHeight + demo.scrollTop === demo.scrollHeight) {
        demo.scrollTop = 0;
      }
    }
  }, timer);
};

export const disabledDate = d => {
  const today = new Date();
  today.setHours(23, 59, 59, 999);
  return d.getTime() > today.getTime();
};

export function downloadFile(downloadUrl, filename) {
  return new Promise(async (resolve, reject) => {
    const response = await request.get(downloadUrl);
    console.log("response", response);
    // const url = window.URL.createObjectURL(new Blob([response.data]));

    const blob = new Blob([response]);

    const objectUrl = URL.createObjectURL(blob);
    const link = document.createElement("a");
    link.download = filename;
    link.href = objectUrl;
    link.click();
    link.remove();

    return;
    // let blob = response.data;
    // const link = document.createElement("a");
    // const body = document.body;

    // link.href = window.URL.createObjectURL(blob);
    // link.download = filename;
    // link.style.display = "none";
    // body.appendChild(link);
    // link.click();
    // body.removeChild(link);

    // window.URL.revokeObjectURL(link.href);
    // resolve(link.href);
  });
}
/**
 * 根据对象数组中的某个属性值进行去重
 * @param array 对象数组，需要去重的数组
 * @param key 指定根据哪个属性进行去重
 * @returns 返回去重后的对象数组
 */
export const unique = (array, key) => {
  // 使用Set实现根据属性值的唯一性
  const _set = [...new Set(array.map(e => e[key]))];
  const deArray = [];
  // 根据_set中的属性值，找出原数组中对应的项
  _set.map(item => {
    deArray.push(array[array.findIndex(val => val[key] === item)]);
  });
  // 返回去重后的数组
  return deArray;
};

/**
 * 根据指定的键合并数组对象
 * @param array 对象数组，需要合并的数组
 * @param key 指定根据哪个属性进行合并
 * @returns 返回合并后的对象数组
 */
export const mergeByKey = (array, key) => {
  const merged = {};
  // 遍历数组，根据key值将对象合并到同一个对象中
  array.forEach(item => {
    if (!merged[item[key]]) {
      merged[item[key]] = { ...item };
    } else {
      // 合并其他属性
      Object.keys(item).forEach(k => {
        if (k !== key) {
          if (merged[item[key]][k]) {
            // 如果已存在该属性，合并为数组
            if (!Array.isArray(merged[item[key]][k])) {
              merged[item[key]][k] = [merged[item[key]][k]];
            }
            merged[item[key]][k].push(item[k]);
          } else {
            merged[item[key]][k] = item[k];
          }
        }
      });
    }
  });

  // 将合并后的对象转换回数组
  return Object.values(merged);
};
// 重命名后的 debounce 函数
export function debounceWithImmediate<T extends (...args: any[]) => any>(
  func: T,
  wait: number,
  immediate = false
): (...args: Parameters<T>) => void {
  let timeoutId: NodeJS.Timeout | null = null;

  return function (this: any, ...args: Parameters<T>) {
    const later = () => {
      timeoutId = null;
      if (!immediate) {
        func.apply(this, args);
      }
    };

    const callNow = immediate && !timeoutId;

    if (timeoutId !== null) {
      clearTimeout(timeoutId);
    }

    timeoutId = setTimeout(later, wait);

    if (callNow) {
      func.apply(this, args);
    }
  };
}
