package com.sckw.core.utils;

import com.sckw.core.common.enums.StringConstant;
import com.sckw.core.model.enums.OrderRuleEnum;
import com.sckw.core.model.enums.RedisOrderGenerateEnum;
import com.sckw.redis.utils.RedissonUtils;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.support.atomic.RedisAtomicLong;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.Objects;

/**
 * @author lfdc
 * @description 物流订单编号生成工具类
 * @date 2023-08-25 16:08:41
 */
@Slf4j
@Component
public class OrderGenerateSeqNoUtils {


    @Resource
    private RedisTemplate redisTemplate;

    /**
     * 物流订单编号生成
     *
     * @param redisOrderGenerateEnum 传入指定枚举的key
     * @param prefix                 业务类别
     * @param orderType              单据创建类型
     * @param level                  所属几级分包
     * @param number                 同级分包次数
     * @return
     */
    public static String getSeqNo(RedisOrderGenerateEnum redisOrderGenerateEnum, OrderRuleEnum prefix, String orderType, String level, String number) {
        if (prefix == null) {
            throw new RuntimeException("Order Generate SeqNo Error");
        }
        Date now = new Date();
        String appendKey = getKey(redisOrderGenerateEnum, prefix, now);
        //设置过期时间，这里设置为当天的23:59:59
        Long secondsDay = DateUtils.getSecondsDay();
        Long seq = generate(appendKey, secondsDay);
        String date = DateUtils.formatDateToYYMMDD(now);
        String sequence = String.format("%04d", seq);
        /**拼接业务编号*/
        String seqNo = prefix.getCode() + date + sequence;
        /**extendBusiness 根据实际业务是否需要 */
        String seqNoEnd = extendBusiness(seqNo, orderType, level, number);
        log.info("KEY:{}, 序列号生成:{}, 过期时间:{}秒", appendKey, seqNo, secondsDay);
        return seqNoEnd;
    }

    private static String extendBusiness(String seqNo, String orderType, String level, String number) {
        return seqNo + orderType + level + number;
    }

    /**
     * 拼接redis key 公共key+[业务标识]+日期
     *
     * @param redisOrderGenerateEnum
     * @param prefix
     * @param date
     * @return
     */
    public static String getKey(RedisOrderGenerateEnum redisOrderGenerateEnum, OrderRuleEnum prefix, Date date) {
        StringBuilder stringBuilder = new StringBuilder();
        StringBuilder appendKey = stringBuilder.append(redisOrderGenerateEnum.getKey()).append(prefix.getCode()).append(DateUtils.formatDate(date));
        return appendKey.toString();
    }

    /**
     * 拼接redis key 公共key+[业务标识]+日期
     *
     * @param redisOrderGenerateEnum
     * @param prefix
     * @param date
     * @return
     */
    public static String getKey(RedisOrderGenerateEnum redisOrderGenerateEnum, OrderRuleEnum prefix, Date date,String lOrderId) {
        StringBuilder stringBuilder = new StringBuilder();
        StringBuilder appendKey = stringBuilder.append(redisOrderGenerateEnum.getKey()).append(prefix.getCode()).append(DateUtils.formatDate(date)).append(lOrderId);
        return appendKey.toString();
    }

    /**
     * 拼接redis key 公共key+[业务标识]不携带日期
     *
     * @param redisOrderGenerateEnum
     * @param prefix
     * @param str
     * @return
     */
    public static String getKeyNotDate(RedisOrderGenerateEnum redisOrderGenerateEnum, OrderRuleEnum prefix, String str) {
        StringBuilder stringBuilder = new StringBuilder();
        StringBuilder appendKey = new StringBuilder();
        if (StringUtils.isNotEmpty(str)) {
            appendKey = stringBuilder.append(redisOrderGenerateEnum.getKey()).append(prefix.getCode()).append(str);
        } else {
            appendKey = stringBuilder.append(redisOrderGenerateEnum.getKey()).append(prefix.getCode());
        }
        return appendKey.toString();
    }

    /**
     * //返回当前redis中的key的最大值
     *
     * @param redisTemplate
     * @param key           redisKey
     * @param expireTime    过期时间
     * @return
     */
    public long generate(RedisTemplate<?, ?> redisTemplate, String key, Date expireTime) {
        //RedisAtomicLong为原子类，根据传入的key和redis链接工厂创建原子类
        RedisAtomicLong counter = new RedisAtomicLong(key, redisTemplate.getConnectionFactory());
        //设置过期时间
        counter.expireAt(expireTime);
        //返回redis中key的值，内部实现下面详细说明
        return counter.incrementAndGet();
    }


    /**
     * 返回当前redis中的key的最大值
     *
     * @param key        redisKey
     * @param expireTime 过期时间
     * @return
     */
    public static long generate(String key, Long expireTime) {
        //RedisAtomicLong counter = new RedisAtomicLong(key, redisTemplate.getConnectionFactory());
//        //设置过期时间
//        counter.expireAt(expireTime);
//        //返回redis中key的值，内部实现下面详细说明
//        return counter.incrementAndGet();
        return RedissonUtils.getAtomicLong(key, expireTime);
    }


    /**
     * redis 根据key需要减一
     *
     * @param redisOrderGenerateEnum
     * @param prefix
     * @return
     */
    public static String getSeqNoMinusOne(RedisOrderGenerateEnum redisOrderGenerateEnum, OrderRuleEnum prefix) {
        if (prefix == null) {
            throw new RuntimeException("Order Generate SeqNo Error");
        }
        Date now = new Date();
        String appendKey = getKey(redisOrderGenerateEnum, prefix, now);
        //设置过期时间，这里设置为当天的23:59:59
        Long secondsDay = DateUtils.getSecondsDay();
        Long seq = getMinusOne(appendKey, secondsDay);
        String date = DateUtils.formatDateToYYMMDD(now);
        String sequence = String.format("%04d", seq);
        /**拼接业务编号*/
        String seqNo = prefix.getCode() + date + sequence;
        log.info("KEY:{}, 序列号生成:{}, 过期时间:{}秒", appendKey, seqNo, secondsDay);
        return seqNo;
    }

    public static long getMinusOne(String key, Long expireTime) {
        long seq = RedissonUtils.decrementAndGet(key, expireTime);
//        RedisAtomicLong counter = new RedisAtomicLong(key, redisTemplate.getConnectionFactory());
//        //设置过期时间
//        counter.expireAt(expireTime);
//        //返回redis中key的值，内部实现下面详细说明
//        return counter.incrementAndGet();
        return seq;
    }


    /**
     * 贸易订单/对账/结算生成规则
     *
     * @param redisOrderGenerateEnum 传入枚举指定的key
     * @param prefix                 业务类别
     * @return
     */
    public static String getOtherSeqNo(RedisOrderGenerateEnum redisOrderGenerateEnum, OrderRuleEnum prefix) {
        if (Objects.isNull(prefix)) {
            throw new RuntimeException("Order Generate SeqNo Error");
        }
        Date now = new Date();
        String appendKey = getKey(redisOrderGenerateEnum, prefix, now);
        //设置过期时间，这里设置为当天的23:59:59
        Long secondsDay = DateUtils.getSecondsDay();
        Long seq = generate(appendKey, secondsDay);
        String date = DateUtils.formatDateToYYMMDD(now);
        String sequence = String.format("%04d", seq);
        /**拼接业务编号*/
        String seqNo = prefix.getCode() + date + sequence;
        log.info("KEY:{}, 序列号生成:{}, 过期时间:{}秒", appendKey, seqNo, secondsDay);
        return seqNo;
    }


    /**
     * 车辆运单编号规则生成
     *
     * @param redisOrderGenerateEnum 传入枚举指定的key
     * @param prefix                 业务类别
     * @return
     */
    public static String getWaybillSeqNo(RedisOrderGenerateEnum redisOrderGenerateEnum, OrderRuleEnum prefix, String pidOrderNo) {
        if (Objects.isNull(prefix)) {
            throw new RuntimeException("Order Generate SeqNo Error");
        }
        String appendKey = getKeyNotDate(redisOrderGenerateEnum, prefix, pidOrderNo);
        //设置过期时间，这里设置为当天的23:59:59
        Long secondsDay = DateUtils.getSecondsDay();
        Long seq = generate(appendKey, secondsDay);
        String sequence = com.sckw.core.utils.StringUtils.addZeroForNum(seq.toString(), 3);
        /**拼接业务编号*/
        String seqNo = pidOrderNo + StringConstant.HYPHEN + sequence;
        log.info("KEY:{}, 序列号生成:{}, 过期时间:{}秒", appendKey, seqNo, secondsDay);
        return seqNo;
    }
}
