package com.sdtool.common.tool;

import com.sdtool.common.base.BaseService;
import com.dySweetFishPlugin.redis.RedisService;
import com.dySweetFishPlugin.sql.TableIdService;
import com.sweetfish.util.AnyValue;
import org.apache.commons.lang3.StringUtils;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.atomic.AtomicLong;

/**
 * Created by jlutt on 2018-03-22.
 *
 * @author jlutt
 */
public class CodeGenerate extends BaseService {

    private static final AtomicLong INCREATOR = new AtomicLong();
    private static final String PAYTIMEFORMAT = "yyyyMMddHHmmss";

    private static final String FILE_TIME_FORMAT = "yyyyMMdd";
    private static final String CARDTIMEFORMAT = "yy";
    private static final long MAX_INCREATOR = 9999L;

    @Resource
    RedisService redisService;

    @Resource
    TableIdService tableIdService;

    @Override
    public void destroy(AnyValue config) {

    }

    private String formatCodeLength(String code, int length) {
        if (code.length() >= length) {
            return code.substring(0, length);
        }
        int padLenth = length - code.length();

        long orgin = Long.parseLong(StringUtils.rightPad("1", padLenth, "0"));
        long bound = Long.parseLong(StringUtils.rightPad("9", padLenth, "9"));

        long randon = ThreadLocalRandom.current().nextLong(orgin, bound);

        return StringUtils.rightPad(String.valueOf(randon), padLenth, "0") + code;
    }

    private String formatMaxLength(String code, int length) {
        if (code.length() >= length) {
            return code.substring(0, length);
        }
        return StringUtils.leftPad(code, length, "0");
    }

    /**
     * 生产商城批量下单文件编号
     * tt 2024-07-30 还是考虑文件上生成一个印界的文件编号，文件编号携带订单信息存入到redis中，这样无论文件名多长都没事，也减少了解析文件名的痛苦，
     * 综合考虑为什么要像老系统和盛大那样搞一长串文件名还要解析，解析个毛线
     * 1、前端请求生成文件名，并和报价接口类似传入订单信息
     * 2、后台接收到订单信息后，生成一个文件编号，并将文件编号和订单json存入redis中，redis的键值以日期区分，每个键值10天后自动过期，兼顾一下存储空间和性能
     * 3、前端获取到编号后，生成文件名，文件名为 [xxx文件编号]-产品名称-报价描述 复制到剪贴板
     * 4、前端批量下单时，前端拖入文件，根据实际情况，方便性的设置收货地址，调用解析订单接口，理论需要支持多个文件名
     * 5、后台获取到多个文件名后，解析文件编号，通过文件编号中的日期到相应的redis键值中查找（如果10天都没下，提示找不到算了，重新下），
     * 查找到订单信息，调用报价和运费计算生成价格（此处需要讨论，因为如果文件多的时候，调用报价会有些慢，还是说，解析到订单列表后，前端循环异步调用报价接口？）
     * 6、在订单所有文件都上传完成后，前端调用批量下单接口
     * 7、后台批量下单接口，需要处理好订单的价格加密信息，运费和对应文件
     *
     * @param prefixCode   编号前缀
     * @param supplierCode 分表
     * @return 文件编号
     */
    public String generateMallFileCode(String prefixCode, long supplierCode) {
        LocalDateTime now = LocalDateTime.now();
        String nowTime = now.format(DateTimeFormatter.ofPattern(FILE_TIME_FORMAT));
        long incre = INCREATOR.accumulateAndGet(1, (x, y) -> (x + y) > MAX_INCREATOR ? 0 : (x + y));
        List<String> time = redisService.time();
        return formatMaxLength(prefixCode, 2) +
                nowTime +
                formatMaxLength(String.valueOf(incre), 4) +
                formatMaxLength(time.get(1), 4);
    }

    /**
     * 生成交易单号 32位的字符串
     */
    public String generatePayOrderCode(String prefixCode, long supplierCode, long partnerId) {
        LocalDateTime now = LocalDateTime.now();
        String nowTime = now.format(DateTimeFormatter.ofPattern(PAYTIMEFORMAT));
        long incre = INCREATOR.accumulateAndGet(1, (x, y) -> (x + y) > MAX_INCREATOR ? 0 : (x + y));
        List<String> time = redisService.time();
        return ERPUtils.encodeSupplierCode(supplierCode) +
                nowTime +
                formatMaxLength(prefixCode, 2) +
                formatCodeLength(String.valueOf(partnerId), 4) +
                formatMaxLength(String.valueOf(incre), 4) +
                formatMaxLength(time.get(1), 4);
    }

    /**
     * 生成德邦快递 渠道单号
     *
     * @return
     */
    public String generateExpressLogisticId(String sign) {
        LocalDateTime now = LocalDateTime.now();
        String nowTime = now.format(DateTimeFormatter.ofPattern(PAYTIMEFORMAT));
        long incre = INCREATOR.accumulateAndGet(1, (x, y) -> (x + y) > MAX_INCREATOR ? 0 : (x + y));
        List<String> time = redisService.time();
        return sign + //4
                nowTime + //14
                "1000" + //4
                formatMaxLength(String.valueOf(incre), 4) + //4
                formatMaxLength(time.get(1), 6); //6
    }

    /**
     * 从单据号中读取supplierCode
     *
     * @param payCode 支付单号
     * @return supplierCode
     */
    public long parseSupplierCodeFromPayOrderCode(String payCode) {
        //取出code前四位
        String supplierStr = payCode.substring(0, 4);
        return ERPUtils.decodeSupplierCode(supplierStr);
    }

    /**
     * 创建随机密码
     *
     * @param len 密码长度
     * @return 密码
     */
    public String createPassWord(int len) {
        final int maxNum = 35;
        StringBuilder sb = new StringBuilder();
        int rdGet;//取得随机数
        char[] str = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
                'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
                'X', 'Y', 'Z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};

        int count = 0;
        while (count < len) {
            rdGet = Math.abs(ThreadLocalRandom.current().nextInt(maxNum));//生成的数最大为62-1
            sb.append(str[rdGet]);
            count++;
        }
        return sb.toString();
    }

    public String generateMallClientCode(long supplierCode) {
        LocalDateTime now = LocalDateTime.now();
        String nowTime = now.format(DateTimeFormatter.ofPattern(CARDTIMEFORMAT));

        int randon = ThreadLocalRandom.current().nextInt(1, 99);

        return "DC" +
                nowTime +
                formatMaxLength(String.valueOf(tableIdService.getArticleId(randon)), 16);
    }

    public String generateMD5Key() {
        return UUID.randomUUID().toString().replace("-", "");
    }
}
