import { Base64 } from "js-base64";

export const getRealativeMosePosition = (
  dom: HTMLElement,
  mousePosition: number[]
) => {
  const rect = dom.getBoundingClientRect();
  return [mousePosition[0] - rect.left, mousePosition[1] - rect.top];
};

// 节流
export const throttle = <T extends (...args: any) => any>(
  fn: T,
  delay: number = 160
) => {
  let previous = 0;

  return function <This>(this: This, ...args: Parameters<T>) {
    const now = Date.now();
    if (now - previous >= delay) {
      fn.apply(this, args);
      previous = now;
    }
  };
};

// 防抖
export const debounce = <T extends (...args: any) => any>(
  fn: T,
  delay: number = 160
) => {
  let timeout: any;

  return function <This>(this: This, ...args: Parameters<T>) {
    clearTimeout(timeout);
    timeout = setTimeout(() => {
      fn.apply(this, args);
    }, delay);
  };
};

export const loadImage = (src: string): Promise<HTMLImageElement> => {
  const img = new Image();
  img.src = src;
  img.crossOrigin = "anonymous";
  return new Promise<HTMLImageElement>((resolve) => {
    img.onload = () => resolve(img);
  });
};

export const mergeFuns = (...fns: (() => void)[]) => {
  return () => {
    fns.forEach((fn) => fn());
  };
};

// 四舍五入保留指定位数
export const round = (num: number, index: number = 2) => {
  const s = Math.pow(10, index);
  return Math.round(num * s) / s;
};

export const numberSplice = (val: number) => {
  const integer = Math.floor(val);
  const decimal = val - integer;

  return [integer, decimal];
};

//经纬度转度°分′秒″
export const toDegrees = (val: number, retain = 4) => {
  let temps = numberSplice(val);
  const d = temps[0];
  temps = numberSplice(temps[1] * 60);
  const m = temps[0];
  const s = round(temps[1] * 60, retain);
  return `${d}°${m}′${s.toFixed(retain)}″`;
};

export const copyText = async (
  text: string,
  fallback?: boolean
): Promise<void> => {
  if (navigator.clipboard && !fallback) {
    let permiss: any;
    try {
      permiss = await navigator.permissions.query({
        name: "geolocation",
      });
      permiss.state === "denied";
    } catch (e) {
      console.error(e);
    }

    if (permiss && permiss.state === "denied") {
      console.error(permiss);
      throw new Error("请授予写入粘贴板权限！");
    } else {
      try {
        await navigator.clipboard.writeText(text);
      } catch (e) {
        console.error("不支持navigator.clipboard.writeText 开启回退");
        return await copyText(text, true);
      }
    }
  } else {
    const textarea = document.createElement("textarea");
    document.body.appendChild(textarea);
    // 隐藏此输入框
    textarea.style.position = "fixed";
    textarea.style.clip = "rect(0 0 0 0)";
    textarea.style.top = "10px";
    // 赋值
    textarea.value = text;
    // 选中
    textarea.select();
    // 复制
    document.execCommand("copy", true);
    // 移除输入框
    document.body.removeChild(textarea);
  }
};

function randomWord(randomFlag: boolean, min: number, max?: number) {
  let str = "";
  let range = min;
  const arr = [
    "0",
    "1",
    "2",
    "3",
    "4",
    "5",
    "6",
    "7",
    "8",
    "9",
    "a",
    "b",
    "c",
    "d",
    "e",
    "f",
    "g",
    "h",
    "i",
    "j",
    "k",
    "l",
    "m",
    "n",
    "o",
    "p",
    "q",
    "r",
    "s",
    "t",
    "u",
    "v",
    "w",
    "x",
    "y",
    "z",
    "A",
    "B",
    "C",
    "D",
    "E",
    "F",
    "G",
    "H",
    "I",
    "J",
    "K",
    "L",
    "M",
    "N",
    "O",
    "P",
    "Q",
    "R",
    "S",
    "T",
    "U",
    "V",
    "W",
    "X",
    "Y",
    "Z",
  ];
  // 随机产生
  if (randomFlag && max) {
    range = Math.round(Math.random() * (max - min)) + min;
  }
  for (let i = 0; i < range; i++) {
    const pos = Math.round(Math.random() * (arr.length - 1));
    str += arr[pos];
  }
  return str;
}

export function encodePwd(str: string) {
  str = Base64.encode(str);
  const NUM = 2;
  const front = randomWord(false, 8);
  const middle = randomWord(false, 8);
  const end = randomWord(false, 8);

  const str1 = str.substring(0, NUM);
  const str2 = str.substring(NUM);

  return front + str2 + middle + str1 + end;
}

const place = /(?:\/:([^/]*))/g;
// 生成/:id 类真实url
export const gendUrl = (tempUrl: string, params: { [key: string]: any }) => {
  let url = "";
  let preIndex = 0;
  let m;
  while ((m = place.exec(tempUrl))) {
    url += tempUrl.substring(preIndex, m.index + 1) + (params[m[1]] || "null");
    preIndex = m.index + m[0].length;
  }
  url += tempUrl.substr(preIndex);
  return url;
};

export const dateFormat = (date: Date, fmt: string) => {
  var o: any = {
    "M+": date.getMonth() + 1, //月份
    "d+": date.getDate(), //日
    "h+": date.getHours(), //小时
    "m+": date.getMinutes(), //分
    "s+": date.getSeconds(), //秒
    "q+": Math.floor((date.getMonth() + 3) / 3), //季度
    S: date.getMilliseconds(), //毫秒
  };
  if (/(y+)/.test(fmt)) {
    fmt = fmt.replace(
      RegExp.$1,
      (date.getFullYear() + "").substr(4 - RegExp.$1.length)
    );
  }
  for (var k in o) {
    if (new RegExp("(" + k + ")").test(fmt)) {
      fmt = fmt.replace(
        RegExp.$1,
        RegExp.$1.length == 1 ? o[k] : ("00" + o[k]).substr(("" + o[k]).length)
      );
    }
  }
  return fmt;
};

let canvas: HTMLCanvasElement;
let ctx: CanvasRenderingContext2D;
export const getTextBound = (
  text: string,
  font: string,
  padding: number[] = [0, 0],
  margin: number[] = [0, 0]
) => {
  if (!canvas) {
    canvas = document.createElement("canvas");
    ctx = canvas.getContext("2d")!;
  }

  ctx.font = font;
  const textMetrics = ctx.measureText(text);

  const width = textMetrics.width + (padding[1] + margin[1]) * 2;
  const fontHeight =
    textMetrics.fontBoundingBoxAscent + textMetrics.fontBoundingBoxDescent;
  console.log(fontHeight);
  const height = fontHeight + (padding[0] + margin[0]) * 2;

  return { width, height };
};

export * from "./tree";
