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

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.cache.redisson.util.RedisLockUtil;
import com.liquidnet.service.adam.constant.AdamRedisConst;
import com.liquidnet.service.adam.dto.AdamMemberCodeParam;
import com.liquidnet.service.adam.dto.vo.AdamMemberCodeVo;
import com.liquidnet.service.adam.dto.vo.AdamMemberVo;
import com.liquidnet.service.adam.dto.vo.AdamUserMemberVo;
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.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

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

import static com.liquidnet.service.adam.constant.AdamRedisConst.LOCK_KEY_UMEMBER_NO;

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

    @Override
    public String createGiftCode(AdamMemberCodeParam param) {
        String mCode, memberNo;
        boolean exists;
        do {
            mCode = MemberUtil.freeCode();
            exists = mongoTemplate.exists(
                    Query.query(Criteria.where("code").is(mCode)), AdamMemberCodeVo.class.getSimpleName()
            );
        } while (exists);

        // 需要主动生成会员编号
        memberNo = getNextMemberNo(param.getMemberId());

        if (StringUtils.isEmpty(memberNo)) return "";

        AdamMemberCode initMemberCode = new AdamMemberCode();
        initMemberCode.setCode(mCode);
        initMemberCode.setType(param.getType());
        initMemberCode.setMemberId(param.getMemberId());
        initMemberCode.setMemberPriceId(param.getMemberPriceId());
        initMemberCode.setMemberNo(memberNo);
        initMemberCode.setState(0);// 0-未使用,1-已使用,2-不可用
        initMemberCode.setCreatedAt(LocalDateTime.now());

        memberCodeMapper.insert(initMemberCode);

        AdamMemberCodeVo vo = AdamMemberCodeVo.getNew().copy(initMemberCode);
        mongoTemplate.insert(vo, AdamMemberCodeVo.class.getSimpleName());

        setMemberCodeVoByCode(mCode, vo);

        return initMemberCode.getCode();
    }

    public String getNextMemberNo(String memberId) {
        long s = System.currentTimeMillis();
        int memberMaxNo = getMaxMemberNo();
        if (-1 == memberMaxNo) {
            if (RedisLockUtil.tryLock(LOCK_KEY_UMEMBER_NO, 1, 3)) {
                memberMaxNo = 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 = getMemberVoByMemberId(memberId);

                        setMaxMemberNo(memberVo.getStartNo());
                    } else {
                        setMaxMemberNo(Integer.parseInt(latestMaxMemberNoVo.getMemberNo()));
                    }
                }
                RedisLockUtil.unlock(LOCK_KEY_UMEMBER_NO);
            } else {
                return null;
            }
        }
        String nextMemberNoStr = String.valueOf(incrMemberNo());
        if (Pattern.matches("([\\d])\\1{" + (nextMemberNoStr.length() - 1) + "}", nextMemberNoStr)) {
            // 不能是完全相同的数字
            nextMemberNoStr = String.valueOf(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 AdamMemberVo getMemberVoByMemberId(String memberId) {
        String key = AdamRedisConst.INFO_MEMBER_CATEGORY.concat(memberId);
        long s = System.currentTimeMillis();
        AdamMemberVo vo = (AdamMemberVo) redisUtil.get(key);
        if (null == vo) {
            s = System.currentTimeMillis();
            vo = mongoTemplate.findOne(
                    Query.query(Criteria.where("memberId").is(memberId).and("state").is(1)),
                    AdamMemberVo.class, AdamMemberVo.class.getSimpleName()
            );
            log.debug("#MDB耗时:{}ms", System.currentTimeMillis() - s);
            if (null != vo) redisUtil.set(key, vo);
        }
        log.debug("#RDM耗时:{}ms", System.currentTimeMillis() - s);
        return vo;
    }

    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);
    }

    public boolean setMemberCodeVoByCode(String memberCode, AdamMemberCodeVo vo) {
        return redisUtil.set(AdamRedisConst.INFO_MEMBER_CODE.concat(memberCode), vo);
    }
}
