import JSEncrypt from "jsencrypt";

/** 数组项交换位置 */
export const swapArrayItem = (arr: any[], index1: number, index2: number) => {
    arr[index1] = arr.splice(index2, 1, arr[index1])[0];
    return arr;
};

/** 从对象中摘取成员 */
export const pluck = <T, K extends keyof T>(t: T, ...k: K[]) => {
    return k.reduce((a, b) => ((a[b] = t[b]), a), {} as Pick<T, K>);
};

/**
 * 为字符串中间加脱敏字符
 * @param text 原始字符串
 * @param start 开始位置
 * @param end 结束位置
 * @param symbol 脱敏字符
 * @returns 脱敏后的字符串
 */
export function textMask(text: string, start: number, end: number, symbol: string = '*') {
    return text.split('').fill(symbol, start, end).join('');
}

/**
 * 为字符串中间加脱敏字符2
 * @param text 原始字符串
 * @param keepHead 保留前导字符数量
 * @param keepTail 保留尾部字符数量
 * @param mark 脱敏标志配置
 * @param mark.symbol 脱敏符号，默认*
 * @param mark.minLen 符号最小长度
 * @param mark.maxLen 符号最大长度
 */
export function textMask2(
    /** 原始字符串 */
    text: string,
    /** 保留前导字符数量 */
    keepHead: number,
    /** 保留尾部字符数量 */
    keepTail: number,
    /** 脱敏标志配置 */
    mark?: {
        /** 脱敏符号，默认* */
        symbol?: string;
        /** 符号最小长度 */
        minLen?: number;
        /** 符号最大长度 */
        maxLen?: number;
    },
) {
    const { symbol, minLen, maxLen } = mark ?? { symbol: '*' };
    const atext = text?.trim() ?? '';
    const sb = symbol ?? '*';
    const ms = minLen ? sb.repeat(minLen) : '';

    if (atext.length === 0) {
        return ms;
    }
    const alen = atext.length;
    const keepLen = keepHead + keepTail;
    if (keepLen < alen) {
        const h = atext.substring(0, keepHead);
        const t = atext.substring(alen - keepTail);
        const markCount = alen - keepLen;
        const sc = Math.min(minLen ?? markCount, maxLen ?? markCount);
        return `${h}${sb.repeat(sc)}${t}`;
    }
    if (keepHead >= alen) {
        return `${atext}${ms}`;
    } else {
        const h = atext.substring(0, keepHead);
        const t = atext.substring(keepHead);
        return `${h}${ms}${t}`;
    }
}

/** 扁平化数组 */
export function flatten<T>(array?: T[][]) {
    let list: T[] = [];
    array?.forEach((t1) => {
        list = [...list, ...t1];
    });
    return list;
}

/**
 * 加密字符串
 * @param str 原始字符串
 * @returns 加密后的字符串
 */
export function encrptRsa(str: string) {
    const publicKey = AppConfig.publicKey;
    const encryptStr = new JSEncrypt();
    encryptStr.setPublicKey(publicKey); // 设置 加密公钥
    return encryptStr.encrypt(str); // 进行加密
}

/** 密码复杂度验证结果类型 */
export type ValidatePasswordComplexityType = {
    /** 整体验证是否通过 */
    isValid?: boolean;
    /** 长度是否验证通过 */
    isLenValid?: boolean;
    /** 数字是否验证通过 */
    isDigitValid?: boolean;
    /** 字母是否验证通过 */
    isLetterValid?: boolean;
    /** 特殊字符是否验证通过 */
    isSpecialValid?: boolean;
    /** 最小长度 */
    minLen: number;
    /** 最大长度 */
    maxLen: number;
    /** 特殊字符 */
    special: string;
};
export const validatePasswordComplexityInititalValue = {
    isValid: false,
    isLenValid: false,
    isDigitValid: false,
    isLetterValid: false,
    isSpecialValid: false,
    minLen: 6,
    maxLen: 32,
    special: '@$!%*#?&+-.,~',
};

/**
 * 验证密码复杂度
 * 长度6~32位，必须1位数字、1位字母、1位特殊字符（@$!%*#?&+-|<>.,~）
 * @param pwd 原密码串
 * @param minLen 最小长度，默认6
 * @param maxLen 最大长度，默认32
 * @returns
 */
export function validatePasswordComplexity(pwd: string, minLen: number = 6, maxLen: number = 32) {
    const ret: ValidatePasswordComplexityType = {
        isValid: true,
        isLenValid: true,
        isDigitValid: true,
        isLetterValid: true,
        isSpecialValid: true,
        minLen,
        maxLen,
        special: validatePasswordComplexityInititalValue.special,
    };

    if (pwd.length < minLen || pwd.length > maxLen) {
        ret.isLenValid = false;
    }
    if (!/[0-9]/.test(pwd)) {
        ret.isDigitValid = false;
    }
    if (!/[a-zA-Z]/.test(pwd)) {
        ret.isLetterValid = false;
    }
    const r = new RegExp(`[${validatePasswordComplexityInititalValue.special}]`);
    if (!r.test(pwd)) {
        ret.isSpecialValid = false;
    }
    ret.isValid = ret.isLenValid && ret.isDigitValid && ret.isLetterValid && ret.isSpecialValid;
    return ret;
}

/**
 * 生成数字字母随机串
 * @param length 长度
 * @returns
 */
export const buildRandomCode = (length: number) => {
    const model = '0123456789abcdefghjkmnpqrstuvwxyz';
    let pwd = '';
    for (let m = 0; m < length; m++) {
        const mi = Math.floor(Math.random() * model.length);
        pwd = `${pwd}${model[mi]}`;
    }
    return pwd;
};

/**
 * 下划线中横线分隔字符串转换为驼峰格式
 * @param {string} value 待转换字符串
 * @param {boolean} [capitalize] 首字母大写
 * @returns
 */
export const kebabToCamelCase = (value: string, capitalize: boolean = false) => {
    let n = value.replace(/[_-][a-zA-z]/g, (str) => str.substr(-1).toUpperCase()).trim() || '';
    if (capitalize && n.length !== 0) {
        n = n.slice(0, 1).toUpperCase() + n.slice(1);
    }
    return n;
};

export const toUnderlineCase = (value: string, upperCase: boolean = false) => {
    const n = value.replace(/[-]/g, () => '_') ?? '';
    if (upperCase) {
        return n.toUpperCase();
    }
    return n;
};

/**
 * 解密 JWT token 的信息
 * @param token jwt token 字符串
 * @returns <any>object
 */
export function decryptJWT(token: string): any {
    const tk = token.replace(/_/g, "/").replace(/-/g, "+");
    const json = decodeURIComponent(escape(window.atob(tk.split(".")[1])));
    const t = JSON.parse(json);
    const dt = new Date();
    t.expireTime = dt.setSeconds(dt.getSeconds() + (t.exp - t.iat) - 30);
    return t;
}

/**
 * 获取元素屏幕 Offset Top
 * @param ele 元素
 */
export function calcElementTop(ele?: HTMLElement | null) {
    if (!ele) {
        return 0;
    }
    let t = 0;
    if (ele.offsetTop > 0 && (ele.offsetHeight + ele.offsetTop) <= (ele.parentElement?.offsetHeight ?? 0)) {
        t += ele.offsetTop;
    }
    if (ele.parentElement) {
        t += calcElementTop(ele.parentElement);
    }
    return t;
}

export default {
    /** 数组项交换位置 */
    swapArrayItem,
    /** 从对象中摘取成员 */
    pluck,
    /** 为字符串中间加脱敏字符 */
    textMask,
    /** 为字符串中间加脱敏字符 */
    textMask2,
    /** 扁平化数组 */
    flatten,
    /** 加密字符串 */
    encrptRsa,
    /** 生成数字字母随机串 */
    buildRandomCode,
    /** 解密 JWT token 的信息 */
    decryptJWT,
    /** 获取元素屏幕 Offset Top */
    calcElementTop,
};
