import type { Router } from 'vue-router';
import type { Action } from 'element-plus';
import { ElMessageBox } from 'element-plus';
import { removeToken } from '@/utils/token-util';
import { uuid } from 'ele-admin-plus';

export function generateGUID(): string {
  let guidStr =  ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, (c: number) =>
    (
      c ^
      (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (c / 4)))
    ).toString(16)
  );
  if (guidStr) {
    return guidStr
  }
  return uuid()
}
/**
 * 退出登录
 * @param route 是否使用路由跳转
 * @param from 登录后跳转的地址
 * @param push 路由跳转方法
 */
export function logout(route?: boolean, from?: string, push?: Router['push']) {
  removeToken();
  if (route && push) {
    push({
      path: '/login',
      query: from ? { from: encodeURIComponent(from) } : void 0
    });
    return;
  }
  // 这样跳转避免再次登录重复注册动态路由, hash 路由模式使用 location.reload();
  const BASE_URL = import.meta.env.BASE_URL;
  const url = BASE_URL + 'login';
  location.replace(from ? `${url}?from=${encodeURIComponent(from)}` : url);
}

/**
 * 显示登录过期退出重新登录弹窗
 * @param from 登录后跳转的地址
 * @param push 路由跳转方法
 */
export function showLogoutConfirm(from: string, push?: Router['push']) {
  ElMessageBox.close();
  ElMessageBox.alert('登录状态已过期, 请退出重新登录!', '系统提示', {
    confirmButtonText: '重新登录',
    callback: (action: Action) => {
      if (action === 'confirm') {
        logout(!!push, from, push);
      }
    },
    type: 'warning',
    draggable: true
  });
}

/**
 * 下载文件
 * @param url 文件地址
 * @param name 文件名
 */
export function downloadUrl(url: string, name: string) {
  const a = document.createElement('a');
  a.href = url;
  a.download = name;
  a.style.display = 'none';
  document.body.appendChild(a);
  a.click();
  document.body.removeChild(a);
}

/**
 * 下载文件
 * @param data 二进制数据
 * @param name 文件名
 * @param type 文件类型
 */
export function download(
  data: Blob | ArrayBuffer | string,
  name: string,
  type?: string
) {
  const blob = new Blob([data], { type: type || 'application/octet-stream' });
  const url = URL.createObjectURL(blob);
  downloadUrl(url, name);
  URL.revokeObjectURL(url);
}

/**
 * 参数转url字符串
 * @param params 参数
 * @param url 需要拼接参数的地址
 */
export function toURLSearch(
  params?: Record<keyof any, any> | null,
  url?: string
): string {
  if (typeof params !== 'object' || params == null) {
    return '';
  }
  const result = transformParams(params)
    .map((d) => `${encodeURIComponent(d[0])}=${encodeURIComponent(d[1])}`)
    .join('&');
  if (!url) {
    return result;
  }
  return (url.includes('?') ? `${url}&` : `${url}?`) + result;
}

/**
 * 参数转表单数据
 * @param params 参数
 */
export function toFormData(params?: Record<keyof any, any> | null): FormData {
  const formData = new FormData();
  if (typeof params !== 'object' || params == null) {
    return formData;
  }
  transformParams(params).forEach((d) => {
    formData.append(d[0], d[1]);
  });
  return formData;
}

/**
 * get请求处理数组和对象类型参数
 * @param params 参数
 */
export function transformParams(params?: Record<string, any> | null) {
  const result: [string, string][] = [];
  if (params != null && typeof params === 'object') {
    Object.keys(params).forEach((key) => {
      const value = params[key];
      if (value != null && value !== '') {
        if (typeof value === 'object' && !isBlobFile(value)) {
          getObjectParamsArray(value).forEach((item) => {
            result.push([`${key}${item[0]}`, item[1]]);
          });
        } else {
          result.push([key, value]);
        }
      }
    });
  }
  return result;
}

/**
 * 对象转参数数组
 * @param obj 对象
 */
export function getObjectParamsArray(obj: Record<string, any>) {
  const result: [string, string][] = [];
  Object.keys(obj).forEach((key) => {
    const value = obj[key];
    if (value != null && value !== '') {
      const name = `[${key}]`;
      if (typeof value === 'object' && !isBlobFile(value)) {
        getObjectParamsArray(value).forEach((item) => {
          result.push([`${name}${item[0]}`, item[1]]);
        });
      } else {
        result.push([name, value]);
      }
    }
  });
  return result;
}

/**
 * 判断是否是文件
 * @param obj 对象
 */
export function isBlobFile(obj: any) {
  return obj != null && (obj instanceof Blob || obj instanceof File);
}

/**
 * 切换主题过渡动画
 * @param callback 执行的方法
 * @param el 过渡动画触发元素
 * @param isOut 是否是退出方向
 * @param isBody 是否在 body 上执行动画
 */
export function doWithTransition(
  callback: () => Promise<void>,
  el?: HTMLElement | null,
  isOut?: boolean,
  isBody?: boolean
) {
  // @ts-ignore
  if (!el || typeof document.startViewTransition !== 'function') {
    callback().catch((e) => console.error(e));
    return;
  }
  document.documentElement.classList.add('disabled-transition');
  el.classList.add('view-transition-trigger');
  el.style.setProperty('view-transition-name', 'view-transition-trigger');
  if (isBody) {
    document.body.style.setProperty('view-transition-name', 'body');
  }
  const rect = el.getBoundingClientRect();
  const x = rect.left + rect.width / 2;
  const y = rect.top + rect.height / 2;
  const endRadius = Math.hypot(
    Math.max(x, innerWidth - x),
    Math.max(y, innerHeight - y)
  );
  // @ts-ignore
  document.startViewTransition(callback).ready.then(() => {
    const clipPath = [
      `circle(0px at ${x}px ${y}px)`,
      `circle(${endRadius}px at ${x}px ${y}px)`
    ];
    const anim = document.documentElement.animate(
      { clipPath: isOut ? [...clipPath].reverse() : clipPath },
      {
        duration: 400,
        easing: 'ease-in',
        pseudoElement: isOut
          ? `::view-transition-old(${isBody ? 'body' : 'root'})`
          : `::view-transition-new(${isBody ? 'body' : 'root'})`
      }
    );
    anim.onfinish = () => {
      document.body.style.removeProperty('view-transition-name');
      el.style.removeProperty('view-transition-name');
      el.classList.remove('view-transition-trigger');
      document.documentElement.classList.remove('disabled-transition');
    };
  });
}

/**
 * 将字节数转换为易读的存储单位（GB, MB, KB, B）
 * @param bytes 字节数量
 * @param precision 可选参数，指定保留的小数位数（默认2位）
 * @returns 格式化的字符串结果（如 '1.23GB', '500B'）
 */
export function formatBytes(bytes: number, precision: number = 2): string {
  // 定义单位常量
  const UNITS = ['B', 'KB', 'MB', 'GB'];
  const UNIT_SCALE = 1024;

  // 处理无效输入
  if (isNaN(bytes) || !isFinite(bytes)) return '0B';
  if (bytes === 0) return '0B';

  // 计算单位级别
  const level = Math.floor(Math.log(bytes) / Math.log(UNIT_SCALE));

  // 获取转换后的值和对应单位
  const unit = UNITS[Math.min(level, UNITS.length - 1)];
  const value = bytes / Math.pow(UNIT_SCALE, level);

  // 智能处理小数部分：
  // 1. 当结果为整数时省略小数部分
  // 2. 保留指定精度但去除末尾多余的0
  const formattedValue = value.toFixed(precision).replace(/(\.0+|0+)$/, '');

  return `${formattedValue}${unit}`;
}

/**
 * 格式化JSON字符串
 * @param {string} jsonString - 需要格式化的JSON字符串
 * @param {number} indentSpaces - 缩进空格数（默认为2）
 * @returns {string} 格式化后的JSON字符串
 * @throws {Error} 当输入不是有效的JSON时抛出错误
 */
export function formatJson(jsonString, indentSpaces = 2) {
  // 验证输入是否为字符串

  // 解析JSON字符串为JavaScript对象
  let parsedObj;
  if (typeof jsonString === 'string') {
    // throw new Error('输入必须是字符串');
    try {
      parsedObj = JSON.parse(jsonString);
    } catch (e: any) {
      throw new Error('无效的JSON格式: ' + e.message);
    }
  } else {
    parsedObj = jsonString;
  }

  // 递归函数来处理格式化
  function format(obj, depth) {
    // 处理基本类型
    if (obj === null) {
      return 'null';
    }

    if (typeof obj === 'boolean' || typeof obj === 'number') {
      return obj.toString();
    }

    if (typeof obj === 'string') {
      return '"' + obj + '"';
    }

    // 处理数组
    if (Array.isArray(obj)) {
      if (obj.length === 0) {
        return '[]';
      }

      const indent = ' '.repeat(depth * indentSpaces);
      const innerIndent = ' '.repeat((depth + 1) * indentSpaces);
      const items: any = [];

      for (let i = 0; i < obj.length; i++) {
        items.push(innerIndent + format(obj[i], depth + 1));
      }

      return '[\n' + items.join(',\n') + '\n' + indent + ']';
    }

    // 处理对象
    const indent = ' '.repeat(depth * indentSpaces);
    const innerIndent = ' '.repeat((depth + 1) * indentSpaces);
    const keys = Object.keys(obj);

    if (keys.length === 0) {
      return '{}';
    }

    const items: any = [];
    for (const key of keys) {
      items.push(innerIndent + '"' + key + '": ' + format(obj[key], depth + 1));
    }

    return '{\n' + items.join(',\n') + '\n' + indent + '}';
  }

  return format(parsedObj, 0);
}
