package com.boman.web.core.utils;

import com.alibaba.fastjson.JSONObject;
import com.boman.common.core.utils.DateUtils;
import com.boman.common.core.utils.SpringUtils;
import com.boman.common.redis.service.RedisService;
import com.boman.web.core.service.common.ICommonService;

import static com.boman.common.core.utils.obj.ObjectUtils.*;
import static com.boman.common.redis.RedisKey.BILL_SQE;
import static com.boman.domain.constant.BillConst.*;

/**
 * @author shiqian
 * @description 单据编号生成
 * @date 2021年03月23日 16:04
 **/
public class BillRuleUtils {

    /**
     * 功能描述: 获取最新的单据编号，根据sys_seq定义的规则
     *
     * @param tableName  业务表
     * @param seqName    gen_table_column中业务表有单据的列对应的seqName
     * @param columnName 业务表有单据的列
     * @return java.lang.String
     */
    public static String getRules(String tableName, String seqName, String columnName) {
        requireNonNull(tableName, "tableName is empty");
        requireNonNull(seqName, "seqName is empty");
        requireNonNull(columnName, "columnName is empty");
        RedisService redisService = SpringUtils.getBean(RedisService.class);
        ICommonService commonService = SpringUtils.getBean(ICommonService.class);

        String sequencesKey = packRulesKey(seqName);
        JSONObject ruleFromRedis = redisService.getCacheObject(sequencesKey);

        String currentValue;
        if (isEmpty(ruleFromRedis)) {
            // 数据库中没有 CURRENT_VALUE
            ruleFromRedis = getSysSeqFromDb(seqName);
            if (isEmpty(ruleFromRedis)) {
                throw new IllegalArgumentException(String.format("表 [%s] 未配置单据生成规则，seqName: %s", tableName, seqName));
            }

            JSONObject newest = commonService.getNewest(tableName);
            if (isEmpty(newest)) {
                String car = ruleFromRedis.getString(SEQ_NAME);
                String rules = getTimeFormat(ruleFromRedis.getString(FORMAT));
                String last = ruleFromRedis.getString(START_NUMBER);
                //  最最原始的数据
                currentValue = car + rules + last;
            } else {
                // 这种情况几乎不会有，除非redis中数据被人手动清空了
                currentValue = resolveRules(ruleFromRedis);
            }
        } else {
//            String beforeValue = ruleFromRedis.getString(CURRENT_VALUE);
            currentValue = resolveRules(ruleFromRedis);
        }

        ruleFromRedis.put(CURRENT_VALUE, currentValue);
        redisService.setCacheObject(sequencesKey, ruleFromRedis);
        return currentValue;
    }

    /**
     * 功能描述: 把001 -> 002
     *
     * @param rule        sys_seq中的数据
     * @return java.lang.String
     */
    private static String resolveRules(JSONObject rule) {
        // 2021-05-05
        String timeFormat = getTimeFormat(rule.getString(FORMAT));
        
        String beforeValue = rule.getString(CURRENT_VALUE);
        if (isEmpty(beforeValue)) {
            return rule.getString(SEQ_NAME) + timeFormat + rule.getString(START_NUMBER);
        }
        
        int totalLength = beforeValue.length();
        int suffixLength = rule.getString(START_NUMBER).length();
        int prefixLength = totalLength - suffixLength;
        
        // 0001
        String suffixValue;
        try {
            suffixValue = beforeValue.substring(prefixLength, totalLength);
        } catch (Exception e) {
            e.printStackTrace();
            return rule.getString(SEQ_NAME) + timeFormat + rule.getString(START_NUMBER);
        }

        // 0002
        String plusOneSuffixValue = strPlusOneByTimeFormat(suffixValue, rule);

        return rule.getString(SEQ_NAME) + timeFormat + plusOneSuffixValue;
    }

    /**
     * 功能描述: getSysSeqFromDb
     *
     * @param seqName seqName
     * @return com.alibaba.fastjson.JSONObject
     */
    private static JSONObject getSysSeqFromDb(String seqName) {
        // 查数据库
        JSONObject condition = new JSONObject();
        condition.put(SEQ_NAME, seqName);
        ICommonService commonService = SpringUtils.getBean(ICommonService.class);
        return commonService.getOneByMap(SYS_SEQ_TABLE_NAME, condition);
    }

    /**
     * 功能描述: 根据sys_seq 中对应的format来获取数据
     *
     * @param format 规则
     * @return java.lang.String
     */
    private static String getTimeFormat(String format) {
        if (YEAR.equals(format)) {
            return DateUtils.getYear();
        } else if (MONTH.equals(format)) {
            return DateUtils.getYyyyMm();
        } else if (DAY.equals(format)) {
            return DateUtils.getYyyyMmDd();
        }

        throw new IllegalArgumentException("sys_seq表中format配置错误，format = " + format);
    }

    /**
     * 功能描述:  eg:
     *              001 -> 002
     *              0001 -> 0002
     *              ......
     *
     * @param value 单据编号后缀的值
     * @param rule 增量
     * @return java.lang.String
     */
    public static String strPlusOneByTimeFormat(String value, JSONObject rule) {
        requireNonNull(rule, "rule is empty");
        requireNonNull(value, "suffixValue is empty");

        Integer increaseNum = rule.getInteger(INCREMENTAL);
        String startNumber = rule.getString(START_NUMBER);
        String timeFormat = rule.getString(FORMAT);
        requireNonNull(increaseNum, "increaseNum is empty");
        requireNonNull(timeFormat, "timeFormat is empty");

        int parseInt;
        try {
            parseInt = Integer.parseInt(value);
        } catch (NumberFormatException e) {
            e.printStackTrace();
            // 默认值
            return startNumber;
        }

        // trip202002020001
        String current = rule.getString(CURRENT_VALUE);
        String seqName = rule.getString(SEQ_NAME);
        int intValue;
        if (YEAR.equals(timeFormat)) {
            String year = DateUtils.getYear();
            // 2020
            String timeFormatValue = getTimeFormatValue(current, seqName, 4);
            intValue = year.equals(timeFormatValue) ? parseInt + increaseNum : Integer.parseInt(startNumber);
        } else if (MONTH.equals(timeFormat)) {
            String yyyyMm = DateUtils.getYyyyMm();
            // 202002
            String timeFormatValue = getTimeFormatValue(current, seqName, 6);
            intValue = yyyyMm.equals(timeFormatValue) ? parseInt + increaseNum : Integer.parseInt(startNumber);
        } else {
            String yyyyMmDd = DateUtils.getYyyyMmDd();
            // 20200202
            String timeFormatValue = getTimeFormatValue(current, seqName, 8);
            intValue = yyyyMmDd.equals(timeFormatValue) ? parseInt + increaseNum : Integer.parseInt(startNumber);
        }

        return String.format("%0" + value.length() + "d", intValue);
    }

    public static String packRulesKey(String seqName) {
        return (BILL_SQE + seqName.toUpperCase()).trim();
    }

    /**
     * 功能描述: 截取中间的时间
     * timeFormatLength=4 => 2020
     * timeFormatLength=6 => 202002
     * timeFormatLength=8 => 20200202
     *
     * @param value            trip202002020001
     * @param seqName          trip
     * @param timeFormatLength 4
     * @return java.lang.String
     */
    public static String getTimeFormatValue(String value, String seqName, int timeFormatLength) {
        // value = trip202002020001
        requireNonNull(value, "value is empty");
        requireNonNull(seqName, "seqName is empty");
        // substring = 202002020001
        String substring = value.substring(seqName.length());
        return substring.substring(0, timeFormatLength);
    }

}
