package com.leromro.core.utils;

import cn.hutool.core.date.DateUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.google.common.hash.HashFunction;
import com.google.common.hash.Hashing;
import java.nio.charset.StandardCharsets;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.util.Date;
import java.util.Random;

import com.leromro.common.exception.ServiceException;
import org.springframework.data.redis.core.RedisTemplate;

public class NoUtil {
    private static final String ORDER_CODE = "OD";
    private static final String PAY_CODE = "PAY";
    private static final String COUPON_ORDER_CODE = "POD";
    private static final String PER_ORDER_CODE = "PR";
    private static final String RETURN_ORDER = "RT";
    private static final String REFUND_ORDER = "RF";
    private static final String ACTIVITY = "AT";
    private static final String PRODUCT = "SN";
    private static final String PARCAL = "BP";
    private static final String PROFIT_SHARE = "PS";
    private static final String TAKE_MONEY = "TX";
    private static final String ORG = "OR";
    private static final String STO = "sto";
    private static final String BILL = "FP";
    private static final String TEMPLATE_NO = "TNO";
    private static final String PACK_NO = "PNO";
    private static final String CON_NO = "DTO";
    private static final String CHECK_NO = "SP";
    private static final String ACOUNT_NO = "WA";
    private static final String CA_NO = "CA";
    private static final String BX_ORDER = "BX";
    private static final String REVENUE_NO = "LX";
    private static final String RENT_CAR_TYPE_NO = "ZC";
    private static final int maxLength = 12;
    private static final int[] r = {7, 9, 6, 2, 8, 1, 3, 0, 5, 4};
    private static final String ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    private static final int ALPHABET_LENGTH = ALPHABET.length();
    private static int counter = 0;

    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(12 - idStr.length())).toString();
    }

    private static String toAutoCode(Integer length) {
        return getRandom(length.intValue()) + "";
    }

    private static String getDateTime() {
        DateFormat sdf = new SimpleDateFormat("yyMMddHHmmssSSS");
        return sdf.format(new Date());
    }

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

    private static synchronized String getCode(Integer userId) {
        return getDateTime() + toCode(Integer.valueOf(userId == null ? 10000 : userId.intValue()));
    }

    private static synchronized String getAutoCode(Integer length) {
        return getDateTime() + toAutoCode(length);
    }

    private static synchronized String getNo(String code) {
        Date date = new Date();
        RedisTemplate<String, Object> redisTemplate = (RedisTemplate) SpringUtil.getBean("redisTemplate");
        Long yyyyMMddHHmmss = Long.valueOf(Long.valueOf(DateUtil.format(date, "yyyyMMddHHmmss")).longValue() * 2);
        String redisKey = "no:" + code + ":" + yyyyMMddHHmmss;
        Long increment = redisTemplate.opsForValue().increment(redisKey);
        if (increment.longValue() == 1) {
            redisTemplate.expire(redisKey, Duration.ofSeconds(1L));
        }
        String s = increment.toString();
        if (s.length() > 6) {
            throw new ServiceException("服务器繁忙,请稍后再试");
        }
        StringBuilder suffix = new StringBuilder();
        for (int i = s.length(); i < 6; i++) {
            suffix.append("0");
        }
        return code + yyyyMMddHHmmss + suffix.toString() + s;
    }

    public static String getOrderNo() {
        return ORDER_CODE + getAutoCode(2);
    }

    public static String getPayNo() {
        return getNo(PAY_CODE);
    }

    public static String getPayRefundNo() {
        return getNo(REFUND_ORDER);
    }

    public static String getCouponOrderNo() {
        return COUPON_ORDER_CODE + getAutoCode(2);
    }

    public static String getOrgNo() {
        return ORG + getAutoCode(2);
    }

    public static String getStoreNo() {
        return STO + getAutoCode(2);
    }

    public static String getCheckNo() {
        return ORG + getAutoCode(2);
    }

    public static String getBillSn() {
        return BILL + getAutoCode(2);
    }

    public static String getPerOrderNo() {
        return PER_ORDER_CODE + getAutoCode(2);
    }

    public static String getActNo(Integer userId) {
        return ACTIVITY + getAutoCode(2);
    }

    public static String getProductNo(Integer userId) {
        return PRODUCT + getAutoCode(2);
    }

    public static String getParcalNo(Integer userId) {
        return PARCAL + getAutoCode(2);
    }

    public static String getProfitShareNo(Integer userId) {
        return PROFIT_SHARE + getAutoCode(2);
    }

    public static String getTakeMoneyNo() {
        return TAKE_MONEY + getAutoCode(2);
    }

    public static String getTemplateNo() {
        return TEMPLATE_NO + getAutoCode(2);
    }

    public static String getCouponPackNo() {
        return PACK_NO + getAutoCode(2);
    }

    public static String getContractActivityNo() {
        return "CA" + getAutoCode(2);
    }

    public static String getContractNo() {
        return CON_NO + getAutoCode(2);
    }

    public static String getAccountNo() {
        return ACOUNT_NO + getAutoCode(2);
    }

    public static String getRefundNo() {
        return REFUND_ORDER + getAutoCode(2);
    }

    public static String getBxNo() {
        return BX_ORDER + getAutoCode(2);
    }

    public static String getRentCarTypeNo() {
        return RENT_CAR_TYPE_NO + getAutoCode(2);
    }

    public static String getRevenueNO() {
        return REVENUE_NO + getAutoCode(2);
    }

    public static String generateUniqueCode() {
        int index1 = (int) (Math.random() * ALPHABET_LENGTH);
        int index2 = (int) (Math.random() * ALPHABET_LENGTH);
        String letters = "" + ALPHABET.charAt(index1) + ALPHABET.charAt(index2);
        HashFunction murmur3_32 = Hashing.murmur3_32();
        StringBuilder append = new StringBuilder().append(letters);
        int i = counter;
        counter = i + 1;
        String hash = murmur3_32.hashString(append.append(i).toString(), StandardCharsets.UTF_8).toString();
        return letters + hash.substring(0, 4);
    }
}