package com.qmth.paper.library.common.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.jeffreyning.mybatisplus.service.MppServiceImpl;
import com.qmth.paper.library.common.entity.BasicBatchNumber;
import com.qmth.paper.library.common.enums.AlphabetEnum;
import com.qmth.paper.library.common.enums.ExceptionResultEnum;
import com.qmth.paper.library.common.lock.LockService;
import com.qmth.paper.library.common.lock.LockType;
import com.qmth.paper.library.common.mapper.BasicBatchNumberMapper;
import com.qmth.paper.library.common.service.BasicBatchNumberService;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author xf
 * @since 2024-08-01
 */
@Service
public class BasicBatchNumberServiceImpl extends MppServiceImpl<BasicBatchNumberMapper, BasicBatchNumber> implements BasicBatchNumberService {

    @Resource
    private LockService lockService;

    @Override
    public BasicBatchNumber getOrAddByExamIdAndUserId(Long examId, Long userId) {
        BasicBatchNumber basicBatchNumber = this.selectByMultiId(new BasicBatchNumber(examId, userId));
        if (basicBatchNumber == null) {
            basicBatchNumber = new BasicBatchNumber(examId, userId, this.getUnusedAlphabet(examId), 0);
            this.saveOrUpdateByMultiId(basicBatchNumber);
        }
        return basicBatchNumber;
    }

    @Override
    public List<BasicBatchNumber> listByExamId(Long examId) {
        QueryWrapper<BasicBatchNumber> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(BasicBatchNumber::getExamId, examId);
        return this.list(queryWrapper);
    }

    @Override
    public void updateBatchNo(Long examId, Long scanUserId, String batchNo) {
        try {
            lockService.waitlock(LockType.UPDATE_BATCH_NO, examId, scanUserId);
            BasicBatchNumber basicBatchNumber = this.getOrAddByExamIdAndUserId(examId, scanUserId);
            String[] batchNoArray = this.splitBatchNo(batchNo);
            if (batchNoArray.length == 2) {
                basicBatchNumber.setAlphabet(batchNoArray[0]);
                basicBatchNumber.setSequence(Integer.valueOf(batchNoArray[1]));
                this.updateByMultiId(basicBatchNumber);
            }
        } catch (Exception e) {
            // 失败不抛出异常
        } finally {
            lockService.unlock(LockType.UPDATE_BATCH_NO, examId, scanUserId);
        }

    }

    private static String[] splitBatchNo(String batchNo) {
        String regex = "[A-Z]{1,2}";
        String[] strings = new String[2];
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(batchNo);
        if (matcher.find()) {
            String alphabet = matcher.group();
            strings[0] = alphabet;
            strings[1] = batchNo.replace(alphabet, "");
        }
        return strings;
    }

    private String getUnusedAlphabet(Long examId) {
        try {
            lockService.waitlock(LockType.GET_ALPHABET, examId);
            // 26个英文字母集合
            List<String> alphabetList = Arrays.stream(AlphabetEnum.values()).map(m -> m.name()).distinct().collect(Collectors.toList());
            List<BasicBatchNumber> basicBatchNumberList = this.listByExamId(examId);
            if (CollectionUtils.isEmpty(basicBatchNumberList)) {
                return alphabetList.get(0);
            } else {
                List<String> usedAlphabetList = basicBatchNumberList.stream().map(BasicBatchNumber::getAlphabet).distinct().collect(Collectors.toList());
                List<String> unusedAlphabetList = (List<String>) CollectionUtils.subtract(alphabetList, usedAlphabetList);
                if (CollectionUtils.isNotEmpty(unusedAlphabetList)) {
                    return unusedAlphabetList.get(0);
                } else {
                    // 一位用完了，使用两位组合
                    for (String s1 : alphabetList) {
                        for (String s2 : alphabetList) {
                            String alphabetDouble = s1.concat(s2);
                            if (usedAlphabetList.contains(alphabetDouble)) {
                                continue;
                            }
                            return alphabetDouble;
                        }
                    }
                    return alphabetList.get(0);
                }
            }
        } catch (Exception e) {
            throw ExceptionResultEnum.ERROR.exception("获取批次号失败：" + e.getMessage());
        } finally {
            lockService.unlock(LockType.GET_ALPHABET, examId);
        }

    }


}
