package cn.iocoder.yudao.framework.common.util.code;

import org.apache.commons.lang3.StringUtils;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;

/**
 * 编码生成器
 */
public class CodeUtils {

    /**
     * 收款单类别头
     */

    private static final String RECEIPT_CODE = "SKD";

    /**
     * 付款单类别头
     */

    private static final String PAYMENT_CODE = "PKD";

    /**
     * 佣金付款单类别头
     */

    private static final String COMMISSION_PAYMENT_CODE = "CPKD";

    /**
     * 快递类别头
     */

    private static final String KD_CODE = "KD";
    /**
     * 退货类别头
     */

    private static final String RETURN_ORDER = "";
    /**
     * 退款类别头
     */

    private static final String REFUND_ORDER = "";


    /**
     * 随即编码
     */

    private static final int[] r = new int[]{7, 9, 6, 2, 8, 1, 3, 0, 5, 4};
    /**
     * 用户id和随机数总长度
     */

    private static final int maxLength = 14;

    /**
     * 根据id进行加密+加随机数组成固定长度编码
     */
    private static String toCode(Integer userId) {
        String idStr = userId.toString();
        StringBuilder idsbs = new StringBuilder();
        for (int i = idStr.length() - 1; i >= 0; i--) {
            idsbs.append(r[idStr.charAt(i) - '0']);
        }
        return idsbs.append(getRandom(maxLength - idStr.length())).toString();
    }


    /**
     * 根据id进行加密+加随机数组成固定长度编码
     */
    private static String toCode(Integer userId, Integer length) {
        String idStr = userId.toString();
        StringBuilder idsbs = new StringBuilder();
        for (int i = idStr.length() - 1; i >= 0; i--) {
            idsbs.append(r[idStr.charAt(i) - '0']);
        }
        return idsbs.append(getRandom(length - idStr.length())).toString();
    }


    /**
     * 生成时间戳
     */
    private static String getDateTime() {
        DateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
        return sdf.format(new Date());
    }

    /**
     * 生成时间戳
     */
    private static String getDateTime(String format) {
        DateFormat sdf = new SimpleDateFormat(format);
        return sdf.format(new Date());
    }

    /**
     * 生成固定长度随机码
     *
     * @param n 长度
     */

    private static long getRandom(long n) {
        long min = 1, max = 9;
        for (int i = 1; i < n; i++) {
            min *= 10;
            max *= 10;
        }
        long rangeLong = (((long) (new Random().nextDouble() * (max - min)))) + min;
        return rangeLong;
    }


    /**
     * 生成不带类别标头的编码
     *
     * @param userId
     */
    private static synchronized String getCode(Integer userId) {
        userId = userId == null ? 10000 : userId;
        return getDateTime() + toCode(userId);
    }


    /**
     * 生成不带类别标头的编码
     *
     * @param userId
     */
    private static synchronized String getCode(Integer userId, Integer length) {
        userId = userId == null ? 10000 : userId;
        return getDateTime() + toCode(userId, length);
    }

    /**
     * 生成订单单单号编码(调用方法)
     *
     * @param userId 网站中该用户唯一ID 防止重复
     */

    public static String getOrderCode(Integer userId) {
        return KD_CODE + getCode(userId);
    }


    /**
     * 生成订单单单号编码(调用方法)
     */

    public static String getCourierNumber() {
        return KD_CODE + getDateTime();
    }


    /**
     * 生成报价单单号编码(调用方法)
     */

    public static String getOfferCode() {
        return getDateTime("yyyyMMddHHmmss") + RECEIPT_CODE + getRandom(5);
    }


    /**
     * 生成退货单号编码（调用方法）
     *
     * @param userId 网站中该用户唯一ID 防止重复
     */
    public static String getReturnCode(Integer userId) {
        return RETURN_ORDER + getCode(userId);
    }


    /**
     * 生成退款单号编码(调用方法)
     *
     * @param userId 网站中该用户唯一ID 防止重复
     */
    public static String getRefundCode(Integer userId) {
        return REFUND_ORDER + getCode(userId);
    }


    /**
     * 功能描述: 自动生成报价单单号
     *
     * @param maxOddNumbers 数据库中的最新单号
     * @param name          报价单姓名
     * @return java.lang.String
     */
    public static String getOddOfferNumbers(String maxOddNumbers, String name) {
        //定义变量(最新的单号)
        String newOddNumber = "";
        //获取当前日期并将其进行格式化
        String formatDate = getDateTime("yyyyMMdd");
        //判断数据中的最大单号是否存在，是否包含当前日期
        if (StringUtils.isNotEmpty(maxOddNumbers) && maxOddNumbers.contains(formatDate)) {
            //截取后四位数
            String endNum = maxOddNumbers.substring(maxOddNumbers.length() - 2);
            //把截取的最后四位数解析为int
            int endIntNum = Integer.parseInt(endNum);
            //在将其加1(自增1)
            int newEndIntNum = 100 + endIntNum + 1;
            //把10000的1去掉，获取到最新的后5位
            String newEndNum = String.valueOf(newEndIntNum).substring(1);
            //生成单号
            newOddNumber = formatDate + name + newEndNum;
            //将单号返回
            return newOddNumber;
        } else {
            //如果为空(第一次生成)或者当前最大订单号的日期与当前日期不一致说明需要重新计数生成单号
            newOddNumber = formatDate + name + "01";
            //将单号返回
            return newOddNumber;
        }
    }

    /**
     * 功能描述: 自动生成跟进单单号. 格式： GJ+年份YYYY+六位数
     *
     * @param maxOddNumbers 数据库中的最新单号
     * @return java.lang.String
     */
    public static String getOddFollowupNumbers(String maxOddNumbers) {
        // 格式： GJ+年份YYYY+六位数
        int numberLength = 12;

        //获取当前日期并将其进行格式化
        String formatYear = getDateTime("yyyy");

        int newEndIntNum;
        //判断数据中的最大单号是否存在，是否包含当前日期
        if (StringUtils.isNotEmpty(maxOddNumbers) && maxOddNumbers.length() == numberLength &&
                maxOddNumbers.substring(2, 6).equals(formatYear)) {
            //截取后四位数
            String endNum = maxOddNumbers.substring(maxOddNumbers.length() - 6);
            //把截取的最后六位数解析为int
            int endIntNum = Integer.parseInt(endNum);
            //在将其加1(自增1)
            newEndIntNum = endIntNum + 1;
        } else {
            // 如果为空(第一次生成)或者当前最大订单号的日期与当前日期不一致说明需要重新计数生成单号
            newEndIntNum = 1;
        }

        //生成单号
        String newOddNumber = String.format("%s%s%06d", "GJ", formatYear, newEndIntNum);
        //将单号返回
        return newOddNumber;
    }


    /**
     * 功能描述: 自动生成收款单单单号
     *
     * @param maxOddNumbers 数据库中的最新单号 SKD00000001
     * @return java.lang.String
     */
    public static String getOddReceiptNumbers(String maxOddNumbers) {
        if (StringUtils.isBlank(maxOddNumbers)) {
            return RECEIPT_CODE + "00000001";
        }
        //截取后八位数
        String endNum = maxOddNumbers.substring(maxOddNumbers.length() - 8);
        //把截取的最后五位数解析为int
        int endIntNum = Integer.parseInt(endNum);
        //在将其加1(自增1)
        int newEndIntNum = 100000000 + endIntNum + 1;
        //把100000000的1去掉，获取到最新的后8位
        String newEndNum = String.valueOf(newEndIntNum).substring(1);
        //将单号返回
        return RECEIPT_CODE + newEndNum;

    }


    /**
     * 功能描述: 自动生成付款单单单号
     *
     * @param maxOddNumbers 数据库中的最新单号 PKD00000001
     * @return java.lang.String
     */
    public static String getOddPayNumbers(String maxOddNumbers) {
        return getOddPayNumbers(PAYMENT_CODE, maxOddNumbers);
    }


    public static String getOddPayNumbers(String code, String maxOddNumbers) {
        if (StringUtils.isBlank(maxOddNumbers)) {
            return code + "00000001";
        }
        //截取后八位数
        String endNum = maxOddNumbers.substring(maxOddNumbers.length() - 8);
        //把截取的最后五位数解析为int
        int endIntNum = Integer.parseInt(endNum);
        //在将其加1(自增1)
        int newEndIntNum = 100000000 + endIntNum + 1;
        //把100000000的1去掉，获取到最新的后8位
        String newEndNum = String.valueOf(newEndIntNum).substring(1);
        //将单号返回
        return code + newEndNum;

    }

    /**
     * 功能描述: 自动生成付款单单单号
     *
     * @param maxOddNumbers 数据库中的最新单号 CPKD00000001
     * @return java.lang.String
     */
    public static String getOddCommissionPayNumbers(String maxOddNumbers) {
        return getOddPayNumbers(COMMISSION_PAYMENT_CODE, maxOddNumbers);

    }


    /**
     * 功能描述: 自动生成空运自编号
     *
     * @param destCountryCode 目的地国家自编号简码
     * @param channelCode     渠道简码
     * @param preChannelCode  上一个渠道简码
     * @param maxOddNumbers   数据库中的最新单号 ECAS1063  注：测试以00000起始，如果存在则以存在的编号做起始
     * @return java.lang.String
     */
    public static String chargeChannelAirSelfNumbers(String destCountryCode, String channelCode, String preChannelCode, String maxOddNumbers) {
        String code = destCountryCode + channelCode;
        if (StringUtils.isBlank(maxOddNumbers)) {
            return code + "00001";
        }
        String preCode = destCountryCode + preChannelCode;
        //截取后面的序号位数
        String endNum = maxOddNumbers.replace(preCode, "");
        //将单号返回
        return code + endNum;

    }


    /**
     * 功能描述: 自动生成空运自编号
     *
     * @param destCountryCode 目的地国家自编号简码
     * @param channelCode     渠道简码
     * @param preChannelCode  上一条渠道简码
     * @param maxOddNumbers   数据库中的最新单号 ECAS1063  注：测试以00000起始，如果存在则以存在的编号做起始
     * @return java.lang.String
     */
    public static String getOddAirSelfNumbers(String destCountryCode, String channelCode, String preChannelCode, String maxOddNumbers) {
        String code = destCountryCode + channelCode;
        if (StringUtils.isBlank(maxOddNumbers)) {
            return code + "00001";
        }
        String preCode = destCountryCode + preChannelCode;
        //截取后八位数
        String endNum = maxOddNumbers.replace(preCode, "");
        int index = endNum.length();
        //把截取的最后五位数解析为int
        int endIntNum = Integer.parseInt(endNum);
        StringBuilder size = new StringBuilder();
        size.append("1");
        for (int i = 0; i < index; i++) {
            size.append("0");
        }
        //在将其加1(自增1)
        int newEndIntNum = Integer.parseInt(size.toString()) + endIntNum + 1;
        //把size的1去掉，获取到后面的位数
        String newEndNum = String.valueOf(newEndIntNum).substring(1);
        //将单号返回
        return code + newEndNum;

    }



    /**
     * 功能描述: 自动生成订单单号
     * 订单号规则（整柜不适用）：
     *
     * Eg：海运拼箱，22年发往尼日利亚的城市lagos——NG2200001L——(国家+运输方式+年份+5位数字+城市)
     * Eg：空运，23年发往尼日利亚的城市lagos——A2200001NA  A+YY（年份）+00000（5位数字，按订单累计，不区分国家）+国家简称(尼日利亚=NG, 加纳=GA，暂时只有这两个国家）
     * Eg：海空联运，22年发往莫桑比克的城市Maputo——MSA220001M——（国家+运输方式+年份+4位数字+城市）
     * <p>
     * 整柜订单号规则：
     * EC+整柜+年份+5位数字
     * Eg：ECF2200001
     *
     * @param maxOddOrderNumbers     数据库中的最新单号
     * @param countryShort           国家简称  尼日利亚：N， 加纳：G， 莫桑比克：M， 肯尼亚：K， 阿联酋：U
     * @param countryAirShort        空运国家简称(尼日利亚=NG, 加纳=GA，暂时只有这两个国家）
     * @param transportShort         运输方式简称  海运拼柜：G， 海运整柜：F， 空运专线：A， 海空联运：SA
     * @param cityShort              城市  Lagos：L， Onisha：O， Maputo：M， Accra：A， Nairobi：N， Dubai：D
     * @param isExternalWarehouse    是否外部仓 外部仓前面需要加上虚拟仓X+国家+运输方式+年份+5位数字+城市(整柜不在此列)
     *                               ➢ 海运拼箱：22年发往莫桑比克的城市Maputo—XMG2200001M
     *                               ➢ 空运专线：22年发往莫桑比克的城市Maputo—XMA2200001M
     *                               ➢ 海空联运：22年发往莫桑比克的城市Maputo—XMSA2200001M——(国家+运输方式+年份+4位数字+城市)
     * @param isConcentrateTransport 是否集运订单 集运订单前面需要加上J+国家+运输方式+年份+5位数字+城市(整柜不在此列)
     *                               *                            ➢ 海运拼箱：22年发往莫桑比克的城市Maputo—JMG2200001M
     *                               *                            ➢ 空运专线：22年发往莫桑比克的城市Maputo—JMA2200001M
     *                               *                            ➢ 海空联运：22年发往莫桑比克的城市Maputo—JMSA2200001M——(国家+运输方式+年份+4位数字+城市)
     * @return java.lang.String
     */
    public static String getOddOrderNumbers(String maxOddOrderNumbers, String countryShort, String countryAirShort, String transportShort, String cityShort,
                                            Boolean isExternalWarehouse, Boolean isConcentrateTransport) {
        //定义变量(最新的单号)
        String newOddOrderNO = "";
        //获取当前日期并将其进行格式化
        String formatDate = getDateTime("yy");
        if (isExternalWarehouse == null) {
            isExternalWarehouse = false;
        }
        if (isConcentrateTransport == null) {
            isConcentrateTransport = false;
        }
        if (countryAirShort == null) {
            countryAirShort = "";
        }
        // 海运拼柜结尾参数是目的地城市代码，专线空运结尾参数是始发地城市代码
        // TODO 整柜订单编号结尾参数暂时不存在，海空联运的结尾暂时同海运拼柜
        int endIndex = (StringUtils.equals(transportShort, "A") ? 0 : cityShort.length());
        //判断数据中的最大单号是否存在，是否包含当前日期
        if (StringUtils.isNotEmpty(maxOddOrderNumbers) && maxOddOrderNumbers.contains(formatDate)) {
            //截取后四位数
            String endNum = StringUtils.equals(transportShort, "F") ? maxOddOrderNumbers.substring(5) :
                    (StringUtils.equals(transportShort, "SA") ? maxOddOrderNumbers.substring(isExternalWarehouse && isConcentrateTransport ? 6 : (isExternalWarehouse || isConcentrateTransport ? 5 : 4), maxOddOrderNumbers.length() - endIndex) :
                            (StringUtils.equals(transportShort, "A") ? maxOddOrderNumbers.substring(isExternalWarehouse && isConcentrateTransport ? 5 : (isExternalWarehouse || isConcentrateTransport ? 4 : 3), maxOddOrderNumbers.length() - endIndex) :
                                    maxOddOrderNumbers.substring(isExternalWarehouse && isConcentrateTransport ? 6 : (isExternalWarehouse || isConcentrateTransport ? 5 : 4), maxOddOrderNumbers.length() - endIndex)));
            //把截取的最后四位数解析为int
            long endIntNum = Long.parseLong(endNum);
            //在将其加1(自增1)
            long newEndIntNum = (StringUtils.equals(transportShort, "SA") ? 10000 : 100000) + endIntNum + 1;
            //把10000或100000的1去掉，获取到最新的后5位
            String newEndNum = String.valueOf(newEndIntNum).substring(1);
            //生成单号
            newOddOrderNO = StringUtils.equals(transportShort, "F") ? "ECF" + formatDate + newEndNum :
                    (isExternalWarehouse ? "X" : "") + (isConcentrateTransport ? "J" : "") +
                            (StringUtils.equals(transportShort, "A") ? transportShort + formatDate + newEndNum + countryAirShort : countryShort + transportShort + formatDate + newEndNum + cityShort);
            //将单号返回
            return newOddOrderNO;
        } else {
            //如果为空(第一次生成)或者当前最大订单号的日期与当前日期不一致说明需要重新计数生成单号
            newOddOrderNO = StringUtils.equals(transportShort, "F") ? "ECF" + formatDate + "00001" :
                    (isExternalWarehouse ? "X" : "") + (isConcentrateTransport ? "J" : "") +
                            (StringUtils.equals(transportShort, "A") ? transportShort + formatDate + "00001" + countryAirShort : countryShort + transportShort + formatDate + "00001" + cityShort);
            //将单号返回
            return newOddOrderNO;
        }
    }

    /**
     * 根据订单编号生成条纹编码
     *
     * @param orderNo 订单编号
     * @param number  箱号
     * @return
     */
    public static String createOrderTagNumber(String orderNo, Integer number) {
        return orderNo + "-" + number.intValue();
    }

    public static String createSplitOrderNo(String orderNo, Integer number) {
        return String.format("%s-%s", orderNo, StringUtils.leftPad(String.valueOf(number), 2, "0"));
    }

    public static Integer getSplitOrderNoSeq(String orderNo) {
        if (orderNo.contains("-")) {
            String s1 = orderNo.split("-")[1];
            if (s1.startsWith("0")) {
                s1 = s1.replace("0", "");
            }
            return Integer.parseInt(s1);
        }
        return 1;
    }

    public static void main(String[] args) {
        String destCountryCode = "ECW";
        String channelCode = "SF";
        String maxOddOrderNumbers = "";
        System.out.println(getOddOrderNumbers("A2300006", "", "GA", "A", "", false, false));
    }

}
