package com.yeejoin.amos.boot.module.jg.biz.utils;

import com.yeejoin.amos.boot.module.jg.api.dto.CodeGenerateDto;
import com.yeejoin.amos.boot.module.jg.api.mapper.CommonMapper;
import org.redisson.api.RBucket;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Component;

import java.util.Arrays;

/**
 * @author Administrator
 */
@Component
public class CodeUtil {


    private RedissonClient redissonClient;

    private CommonMapper commonMapper;

    /**
     * 特殊独立的区县
     */
    private static String[] EXCLUSION_CITY_REGIONS = {"610403", "610581"};


    public CodeUtil(RedissonClient redissonClient, CommonMapper commonMapper) {
        this.redissonClient = redissonClient;
        this.commonMapper = commonMapper;
    }


    /**
     * 按照特种设备代码规范生成 设备代码
     *
     * @param codeGenerateDto 生成代码需要的数据
     * @return 设备基本代码（4位）+ 行政区域代码（6位）+制造年份（4位）+ 制造顺序号（4位）
     */
    public String generateEquipmentCode(CodeGenerateDto codeGenerateDto) {
        // 根据区县或者地市级的接收机构代码获取地市级的行政区域代码
        String regionCode = this.getCityRegionCode(codeGenerateDto.getReceiveCompanyCode());
        // 并发锁处理
        String lockKey = this.buildLockKey(codeGenerateDto.getEquipBaseCode(), regionCode, codeGenerateDto.getYear());
        RLock rLock = redissonClient.getLock(lockKey);
        try {
            rLock.lock();
            // 获取当前已经使用过的序列号
            RBucket<Long> rBucket = redissonClient.getBucket(this.buildManufactureNumberKey(lockKey));
            // 初始化逻辑，初始化为0（编号1开始）
            if (rBucket.get() == null) {
                rBucket.set(0L);
            }
            long currentNumber = rBucket.get();
            long nextNumber = currentNumber + 1;
            // 使用后redis序列号+1
            rBucket.set(nextNumber);
            return this.buildEquipmentCode(codeGenerateDto.getEquipBaseCode(), regionCode, codeGenerateDto.getYear(), nextNumber);
        } finally {
            if (rLock.isHeldByCurrentThread()) {
                rLock.unlock();
            }
        }
    }

    public void initCode(CodeGenerateDto codeGenerateDto ,Long intNumber){
        // 根据区县或者地市级的接收机构代码获取地市级的行政区域代码
        String regionCode = this.getCityRegionCode(codeGenerateDto.getReceiveCompanyCode());
        String lockKey = this.buildLockKey(codeGenerateDto.getEquipBaseCode(), regionCode, codeGenerateDto.getYear());
        RBucket<Long> rBucket = redissonClient.getBucket(this.buildManufactureNumberKey(lockKey));
        // 初始化逻辑，初始化为0（编号1开始）
        if(intNumber != null){
            rBucket.set(intNumber);
        } else {
            rBucket.set(0L);
        }
    }

    /**
     * 获取地市级的行政审批区域代码
     *
     * @param receiveCompanyCode 接收机构的行政区域代码
     * @return 地市级行政审批区域代码
     */
    private String getCityRegionCode(String receiveCompanyCode) {
        // 需求《需要注意的是其中的行政区域代码直到地市一级，西咸、杨凌、韩城用自己的》,西咸组织机构独立的所以不需要单独排除
        if (Arrays.asList(EXCLUSION_CITY_REGIONS).contains(receiveCompanyCode)) {
            return receiveCompanyCode;
        } else {
            return commonMapper.selectCityCompanyCode(receiveCompanyCode, EXCLUSION_CITY_REGIONS);
        }
    }

    private String buildEquipmentCode(String equipBaseCode, String regionCode, String year, long nextNumber) {
        String manufactureNumber = longCode2StrCode(nextNumber);
        return String.format("%s%s%s%s", equipBaseCode, regionCode, year, manufactureNumber);
    }

    private String longCode2StrCode(long nextNumber) {
        if (nextNumber >= 10000) {
            char prefix = (char) ('A' + (nextNumber - 10000) / 1000);
            return prefix + "" + String.format("%03d", (nextNumber - 10000) % 1000);
        } else {
            return String.format("%04d", nextNumber);
        }
    }


    private String buildManufactureNumberKey(String lockKey) {
        return "MANUFACTURE_NUMBER_KEY:" + lockKey;
    }

    private String buildLockKey(String equipBaseCode, String regionCode, String year) {
        return equipBaseCode + regionCode + year;
    }
}
