package com.cool.store.utils;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.RandomUtil;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.web.util.HtmlUtils;

import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.concurrent.ThreadLocalRandom;
import java.util.regex.Pattern;

import static com.cool.store.utils.CoolDateUtils.DATE_FORMAT_SEC;

/**
 * @author zhangchenbiao
 * @FileName: AesUtil
 * @Description:字符串相关操作
 * @date 2023-05-29 14:28
 */

public class StringUtil extends org.apache.commons.lang3.StringUtils {
    private static final char UPPER_A = 'A';
    private static final char LOWER_A = 'a';
    private static final char UPPER_Z = 'Z';
    private static final char LOWER_Z = 'z';

    public static final String REPLACE_0 = "{0}";
    public static final String REPLACE_1 = "{1}";
    public static final String REPLACE_2 = "{2}";
    public static final String REPLACE_3 = "{3}";
    public static final String REPLACE_4 = "{4}";
    public static final String REPLACE_5 = "{5}";

    private static final byte[] DIGITS = {
            '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'
    };
    /**
     * 特殊字符正则，sql特殊字符和空白符
     */
    private static final Pattern SPECIAL_CHARS_REGEX = Pattern.compile("[`'\"|/,;()-+*%#·•�　\\s]");
    /**
     * 随机字符串因子
     */
    private static final String INT_STR = "0123456789";
    private static final String STR_STR = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
    private static final String ALL_STR = INT_STR + STR_STR;

    /**
     * 首字母变小写
     *
     * @param str 字符串
     * @return {String}
     */
    public static String firstCharToLower(String str) {
        char firstChar = str.charAt(0);
        if (firstChar >= UPPER_A && firstChar <= UPPER_Z) {
            char[] arr = str.toCharArray();
            arr[0] += (LOWER_A - UPPER_A);
            return new String(arr);
        }
        return str;
    }

    /**
     * 首字母变大写
     *
     * @param str 字符串
     * @return {String}
     */
    public static String firstCharToUpper(String str) {
        char firstChar = str.charAt(0);
        if (firstChar >= LOWER_A && firstChar <= LOWER_Z) {
            char[] arr = str.toCharArray();
            arr[0] -= (LOWER_A - UPPER_A);
            return new String(arr);
        }
        return str;
    }

    public static String appendParams(String url, Map<String, Object> params) {
        if (StringUtil.isBlank(url)) {
            return "";
        } else if (CollectionUtils.isEmpty(params)) {
            return url.trim();
        } else {
            StringBuilder sb = new StringBuilder(200);
            params.forEach((k, v) -> sb.append(k).append("=").append(v).append("&"));
            sb.deleteCharAt(sb.length() - 1);
            url = url.trim();
            int length = url.length();
            int index = url.indexOf("?");
            if (index > -1) {
                if ((length - 1) == index) {
                    url += sb.toString();
                } else {
                    url += "&" + sb.toString();
                }
            } else {
                url += "?" + sb.toString();
            }
            return url;
        }
    }

    /**
     * 生成uuid，采用 jdk 9 的形式，优化性能
     *
     * @return UUID
     */
    public static String getUUID() {
        ThreadLocalRandom random = ThreadLocalRandom.current();
        long lsb = random.nextLong();
        long msb = random.nextLong();
        byte[] buf = new byte[32];
        formatUnsignedLong(lsb, buf, 20, 12);
        formatUnsignedLong(lsb >>> 48, buf, 16, 4);
        formatUnsignedLong(msb, buf, 12, 4);
        formatUnsignedLong(msb >>> 16, buf, 8, 4);
        formatUnsignedLong(msb >>> 32, buf, 0, 8);
        return new String(buf, StandardCharsets.UTF_8);
    }

    private static void formatUnsignedLong(long val, byte[] buf, int offset, int len) {
        int charPos = offset + len;
        int radix = 1 << 4;
        int mask = radix - 1;
        do {
            buf[--charPos] = DIGITS[((int) val) & mask];
            val >>>= 4;
        } while (charPos > offset);
    }

    /**
     * 转义HTML用于安全过滤
     *
     * @param html html
     * @return {String}
     */
    public static String escapeHtml(String html) {
        return HtmlUtils.htmlEscape(html);
    }

    /**
     * 清理字符串，清理出某些不可见字符和一些sql特殊字符
     *
     * @param txt 文本
     * @return {String}
     */
    @Nullable
    public static String cleanText(@Nullable String txt) {
        if (txt == null) {
            return null;
        }
        return SPECIAL_CHARS_REGEX.matcher(txt).replaceAll(StringUtil.EMPTY);
    }

    /**
     * 获取标识符，用于参数清理
     *
     * @param param 参数
     * @return 清理后的标识符
     */
    @Nullable
    public static String cleanIdentifier(@Nullable String param) {
        if (param == null) {
            return null;
        }
        StringBuilder paramBuilder = new StringBuilder();
        for (int i = 0; i < param.length(); i++) {
            char c = param.charAt(i);
            if (Character.isJavaIdentifierPart(c)) {
                paramBuilder.append(c);
            }
        }
        return paramBuilder.toString();
    }

    /**
     * 随机数生成
     *
     * @param count 字符长度
     * @return 随机数
     */
    public static String random(int count) {
        return random(count, RandomType.ALL);
    }

    /**
     * 随机数生成
     *
     * @param count      字符长度
     * @param randomType 随机数类别
     * @return 随机数
     */
    public static String random(int count, RandomType randomType) {
        if (count == 0) {
            return "";
        }
        Assert.isTrue(count > 0, "Requested random string length " + count + " is less than 0.");
        final ThreadLocalRandom random = ThreadLocalRandom.current();
        char[] buffer = new char[count];
        for (int i = 0; i < count; i++) {
            if (RandomType.INT == randomType) {
                buffer[i] = INT_STR.charAt(random.nextInt(INT_STR.length()));
            } else if (RandomType.STRING == randomType) {
                buffer[i] = STR_STR.charAt(random.nextInt(STR_STR.length()));
            } else {
                buffer[i] = ALL_STR.charAt(random.nextInt(ALL_STR.length()));
            }
        }
        return new String(buffer);
    }

    public enum RandomType {
        /**
         * INT STRING ALL
         */
        INT, STRING, ALL;
    }

    /**
     * 左补位
     *
     * @param str    字符串
     * @param length 总位数
     * @return Result 补位后的字符串
     */
    public static String addZeroForNum(String str, int length) {
        int strLen = str.length();
        if (strLen < length) {
            while (strLen < length) {
                StringBuffer sb = new StringBuffer();
                sb.append("0").append(str);
                str = sb.toString();
                strLen++;
            }
        }
        return str;
    }

    /**
     * 生成房间号
     * @param dateTime
     * @return
     */
    public static String generateRoomId(String dateTime) {
        //YYYY-MM-DD HH:mm:ss 转换成yyyyMMddHHmmss
        //使用 YYMMDD 是错误的
        //String format = DateUtil.format(DateUtil.parse(dateTime, "YYYY-MM-dd HH:mm:ss"), "YYMMDD");
        String format = DateUtil.format(DateUtil.parse(dateTime, DATE_FORMAT_SEC), "yyMMdd");
        String numbers = RandomUtil.randomNumbers(4);
        return format + numbers;
    }
}
