package com.liquidnet.client.admin.zhengzai.adam.service.impl;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.liquidnet.client.admin.zhengzai.adam.service.IAdamMemberCodeAdminService;
import com.liquidnet.common.cache.redis.util.RedisUtil;
import com.liquidnet.common.exception.LiquidnetServiceException;
import com.liquidnet.commons.lang.util.CollectionUtil;
import com.liquidnet.service.adam.constant.AdamRedisConst;
import com.liquidnet.service.adam.dto.param.admin.AdamMemberCodeGenParam;
import com.liquidnet.service.adam.dto.vo.AdamMemberCodeVo;
import com.liquidnet.service.adam.entity.AdamMemberCode;
import com.liquidnet.service.adam.mapper.AdamMemberCodeMapper;
import com.liquidnet.service.adam.util.MemberUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;

@Slf4j
@Service
public class AdamMemberCodeAdminServiceImpl extends ServiceImpl<AdamMemberCodeMapper, AdamMemberCode> implements IAdamMemberCodeAdminService {
    @Autowired
    AdamMemberCodeMapper memberCodeMapper;
    @Autowired
    RedisUtil redisUtil;

    @Override
    public boolean createGiftCode(AdamMemberCodeGenParam param) {
        List<AdamMemberCode> memberCodeList = new ArrayList<>();
        ArrayList<String> codeList = CollectionUtil.arrayListString();
        Integer genNum = param.getGenNum();
        LocalDateTime now = LocalDateTime.now();
        for (int i = 0; i < genNum; i++) {
            String mCode;
            boolean exists;
            do {
                mCode = MemberUtil.freeCode();
                String key = AdamRedisConst.INFO_MEMBER_CODE.concat(mCode);
                exists = redisUtil.hasKey(key);
            } while (exists);

            AdamMemberCode initMemberCode = new AdamMemberCode();
            initMemberCode.setCode(mCode);
            initMemberCode.setType(1);
            initMemberCode.setMemberId(param.getMemberId());
            initMemberCode.setMemberPriceId(param.getMemberPriceId());
            // 需要主动生成会员编号
            //initMemberCode.setMemberNo(getNextMemberNo(param.getMemberId()));
            initMemberCode.setState(0);// 状态[0-可用|1-已用|2-无效|3-过期｜4-失效｜5-退回]
            initMemberCode.setValidity(param.getValidity());
            initMemberCode.setEffectAt(now);
            initMemberCode.setExpireAt(now.plusDays(param.getValidity()).withHour(23).withMinute(59).withSecond(59));
            initMemberCode.setCreatedAt(now);

            memberCodeList.add(initMemberCode);
            codeList.add(mCode);

            //redisUtil.set(AdamRedisConst.INFO_MEMBER_CODE.concat(mCode), AdamMemberCodeVo.getNew().copy(initMemberCode));
        }

        if (this.saveBatch(memberCodeList, memberCodeList.size())) {
            List<AdamMemberCode> list = this.list(
                    Wrappers.lambdaQuery(AdamMemberCode.class).in(AdamMemberCode::getCode, codeList)
                            .eq(AdamMemberCode::getState, 0).eq(AdamMemberCode::getCreatedAt, now)
            );
            list.forEach(r -> {
                r.setMemberNo(getNextMemberNo(param.getMemberId()));

                redisUtil.set(AdamRedisConst.INFO_MEMBER_CODE.concat(r.getCode()), AdamMemberCodeVo.getNew().copy(r));
            });
            this.updateBatchById(list, list.size());
            return true;
        }
        return false;
    }

    public String getNextMemberNo(String memberId) {
        long s = System.currentTimeMillis();
        int memberMaxNo = this.getMaxMemberNo();
        if (-1 == memberMaxNo) {
            // TODO: 2021/7/29 降级DB
            throw new LiquidnetServiceException();
//            if (RedisLockUtil.tryLock(LOCK_KEY_UMEMBER_NO, 1, 3)) {
//                memberMaxNo = adamRdmService.getMaxMemberNo();
//                if (-1 == memberMaxNo) {
////                    Query query = Query.query(Criteria.where("memberId").is(memberId)).with(Sort.by(Sort.Direction.DESC, "memberNo")).limit(1);
////
////                    AdamUserMemberVo latestMaxMemberNoVo = mongoTemplate.findOne(query, AdamUserMemberVo.class, AdamUserMemberVo.class.getSimpleName());
////
////                    if (null == latestMaxMemberNoVo) {
//                        AdamMemberVo memberVo = adamRdmService.getMemberVoByMemberId(memberId);
//
//                        adamRdmService.setMaxMemberNo(memberVo.getStartNo());
////                    } else {
////                        adamRdmService.setMaxMemberNo(Integer.parseInt(latestMaxMemberNoVo.getMemberNo()));
////                    }
//                }
//                RedisLockUtil.unlock(LOCK_KEY_UMEMBER_NO);
//            } else {
//                return null;
//            }
        }
        String nextMemberNoStr = String.valueOf(this.incrMemberNo());
        while (Pattern.matches("([\\d])\\1{" + (nextMemberNoStr.length() - 1) + "}", nextMemberNoStr)) {
            // 不能是完全相同的数字
            nextMemberNoStr = String.valueOf(this.incrMemberNo());
        }
        log.debug("#MNO耗时:{}ms", System.currentTimeMillis() - s);
        return nextMemberNoStr;
    }

    private int getMaxMemberNo() {
        Object o = redisUtil.get(AdamRedisConst.INCR_MEMBER_NO);
        return null == o ? -1 : (int) o;
    }

    public boolean setMaxMemberNo(int val) {
        return redisUtil.set(AdamRedisConst.INCR_MEMBER_NO, val);
    }

    public int incrMemberNo() {
        return (int) redisUtil.incr(AdamRedisConst.INCR_MEMBER_NO, 1);
    }
}
