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

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.liquidnet.client.admin.common.utils.DateUtils;
import com.liquidnet.client.admin.common.utils.ShiroUtils;
import com.liquidnet.client.admin.zhengzai.adam.service.IAdamMemberPriceAdminService;
import com.liquidnet.client.admin.zhengzai.candy.service.ICandyCouponAdminService;
import com.liquidnet.client.admin.zhengzai.candy.service.ICandyCouponRuleAdminService;
import com.liquidnet.client.admin.zhengzai.candy.service.ICandyMgtCouponAdminService;
import com.liquidnet.common.cache.redis.util.RedisUtil;
import com.liquidnet.common.exception.LiquidnetServiceException;
import com.liquidnet.commons.lang.util.IDGenerator;
import com.liquidnet.service.adam.constant.AdamRedisConst;
import com.liquidnet.service.adam.dto.vo.AdamMemberRightsCouponRuleVo;
import com.liquidnet.service.adam.dto.vo.AdamMemberRightsCouponVo;
import com.liquidnet.service.adam.entity.AdamMemberPrice;
import com.liquidnet.service.candy.dto.admin.*;
import com.liquidnet.service.candy.entity.CandyCoupon;
import com.liquidnet.service.candy.entity.CandyCouponRule;
import com.liquidnet.service.candy.entity.CandyMgtCoupon;
import com.liquidnet.service.candy.mapper.CandyCouponMapper;
import com.liquidnet.service.candy.mapper.CandyMgtCouponMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;

@Slf4j
@Service
public class CandyMgtCouponAdminServiceImpl extends ServiceImpl<CandyMgtCouponMapper, CandyMgtCoupon> implements ICandyMgtCouponAdminService {
    @Autowired
    private CandyMgtCouponMapper candyMgtCouponMapper;
    @Autowired
    private CandyCouponMapper candyCouponMapper;

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private ICandyCouponAdminService candyCouponAdminService;
    @Autowired
    private ICandyCouponRuleAdminService candyCouponRuleAdminService;
    @Autowired
    private ICandyMgtCouponAdminService candyMgtCouponAdminService;
    @Autowired
    private IAdamMemberPriceAdminService adamMemberPriceAdminService;

    @Override
    public boolean saveMgtCouponForMemberRights(CandyMemberCouponBuildParam parameter) {
        String memberId = parameter.getMemberId(), operator = ShiroUtils.getLoginName();
        LocalDateTime nowTime = LocalDateTime.now();

        LambdaQueryWrapper<AdamMemberPrice> memberPriceLambdaQueryWrapper = Wrappers.lambdaQuery(AdamMemberPrice.class)
                .eq(AdamMemberPrice::getMemberId, memberId).eq(AdamMemberPrice::getState, 1);
        AdamMemberPrice memberPrice = adamMemberPriceAdminService.getOne(memberPriceLambdaQueryWrapper);

        CandyCoupon initCoupon = new CandyCoupon();
        initCoupon.setCouponId(IDGenerator.nextMilliId());
        initCoupon.setState(1);
        initCoupon.setTitle(parameter.getTitle());
        initCoupon.setLabel(parameter.getLabel());
        initCoupon.setNotice("会员权益");
        initCoupon.setExclusive(1);
        initCoupon.setBusiType(parameter.getBusiType());
        initCoupon.setCouType(parameter.getCouType());
        initCoupon.setBindType(1);// 领取方式[0-用户输入兑换｜1-发放至用户]
        //initCoupon.setDiscount();
        initCoupon.setValFace(parameter.getValFace());
        initCoupon.setValOver(parameter.getValOver());
        initCoupon.setValMinus(parameter.getValMinus());
        initCoupon.setOverlay(parameter.getOverlay());
        initCoupon.setValidity(memberPrice.getDays());
        //initCoupon.setRedeemValidity();
        //initCoupon.setRedeemStart();
        //initCoupon.setRedeemStop();
        //initCoupon.setEffectAt();
        //initCoupon.setExpireAt();
        initCoupon.setOperator(operator);
        initCoupon.setCreatedAt(nowTime);


        List<CandyCouponRuleBuildParam> couponRuleList = parameter.getCouponRuleList();
        List<CandyCouponRule> initCouponRuleList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(couponRuleList)) {
            couponRuleList.forEach(r -> {
                CandyCouponRule initCouponRule = new CandyCouponRule();
                initCouponRule.setCruleId(IDGenerator.nextTimeId2());
                initCouponRule.setCouponId(initCoupon.getCouponId());
                initCouponRule.setUseScope(r.getUseScope());
                initCouponRule.setBusiName(r.getBusiName());
                initCouponRule.setBusiId(r.getBusiId());
                initCouponRule.setState(1);

                initCouponRuleList.add(initCouponRule);
            });
        }


        CandyMgtCoupon initMgtCoupon = new CandyMgtCoupon();
        initMgtCoupon.setMcouponId(parameter.getMrightsId());
        initMgtCoupon.setCouponId(initCoupon.getCouponId());
        initMgtCoupon.setState(10);// 发放状态[0-未发放|1-已发放|2-无效｜9-发放中|10-会员礼包初始模版]

        initMgtCoupon.setEventAmt(parameter.getEventAmt());
        initMgtCoupon.setEventType(2);
        //initMgtCoupon.setEventLimit();
        //initMgtCoupon.setEventAt();
        initMgtCoupon.setOperator(operator);
        initMgtCoupon.setCreatedAt(nowTime);

        return candyMgtCouponAdminService.saveMgtCouponInfo(initCoupon, initMgtCoupon, initCouponRuleList);
    }

    @Override
    public boolean editMgtCouponForMemberRights(CandyMemberCouponBuildParam parameter) {
        String couponId = parameter.getCouponId(), operator = ShiroUtils.getLoginName();
        LocalDateTime nowTime = LocalDateTime.now();

        LambdaQueryWrapper<CandyCoupon> candyCouponLambdaQueryWrapper = Wrappers.lambdaQuery(CandyCoupon.class)
                .eq(CandyCoupon::getCouponId, couponId)
                .eq(CandyCoupon::getState, 1)
                .eq(CandyCoupon::getExclusive, 1);
        if (candyCouponAdminService.count(candyCouponLambdaQueryWrapper) > 0) {
            CandyCoupon updateCoupon = new CandyCoupon();
            updateCoupon.setCouponId(couponId);

            updateCoupon.setTitle(parameter.getTitle());
            updateCoupon.setExclusive(1);
            updateCoupon.setBusiType(parameter.getBusiType());
            updateCoupon.setCouType(parameter.getCouType());
            updateCoupon.setValFace(parameter.getValFace());
            updateCoupon.setValOver(parameter.getValOver());
            updateCoupon.setValMinus(parameter.getValMinus());
            updateCoupon.setOverlay(parameter.getOverlay());
            updateCoupon.setOperator(operator);
            updateCoupon.setUpdatedAt(nowTime);


            List<CandyCouponRuleBuildParam> couponRuleList = parameter.getCouponRuleList();
            List<CandyCouponRule> initCouponRuleList = new ArrayList<>();
            if (!CollectionUtils.isEmpty(couponRuleList)) {
                couponRuleList.forEach(r -> {
                    CandyCouponRule initCouponRule = new CandyCouponRule();
                    initCouponRule.setCruleId(IDGenerator.nextTimeId2());
                    initCouponRule.setCouponId(couponId);
                    initCouponRule.setUseScope(r.getUseScope());
                    initCouponRule.setBusiName(r.getBusiName());
                    initCouponRule.setBusiId(r.getBusiId());
                    initCouponRule.setState(1);

                    initCouponRuleList.add(initCouponRule);
                });
            }


            CandyMgtCoupon updateMgtCoupon = new CandyMgtCoupon();
            updateMgtCoupon.setMcouponId(parameter.getMrightsId());

            updateMgtCoupon.setEventAmt(parameter.getEventAmt());
            updateMgtCoupon.setOperator(operator);
            updateMgtCoupon.setUpdatedAt(nowTime);

            return candyMgtCouponAdminService.updateMgtCouponInfo(updateCoupon, updateMgtCoupon, initCouponRuleList);
        }
        return false;
    }

    @Override
    public boolean saveMgtCouponForCouponBuild(CandyMgtCouponBuildParam parameter) {
        String eventAtStr = parameter.getEventAt();
        LocalDateTime nowTime = LocalDateTime.now();
        LocalDateTime eventAt = StringUtils.isEmpty(eventAtStr.trim()) ? nowTime
                : LocalDateTime.parse(eventAtStr, DateTimeFormatter.ofPattern(DateUtils.YYYY_MM_DD_HH_MM_SS));

        CandyCoupon initCoupon = new CandyCoupon();
        initCoupon.setCouponId(IDGenerator.nextMilliId());
        initCoupon.setState(1);
        initCoupon.setTitle(parameter.getTitle());
        initCoupon.setLabel(parameter.getLabel());
        initCoupon.setNotice(parameter.getNotice());
        initCoupon.setExclusive(0);
        initCoupon.setBusiType(parameter.getBusiType());
        initCoupon.setCouType(parameter.getCouType());
        initCoupon.setBindType(parameter.getBindType());
        initCoupon.setDiscount(parameter.getDiscount());
        initCoupon.setValFace(parameter.getValFace());
        initCoupon.setValOver(parameter.getValOver());
        initCoupon.setValMinus(parameter.getValMinus());
        initCoupon.setOverlay(parameter.getOverlay());
        initCoupon.setValidity(parameter.getValidity());
        initCoupon.setRedeemValidity(parameter.getRedeemValidity());
        initCoupon.setRedeemStart(eventAt.with(LocalTime.MIN));
        initCoupon.setRedeemStop(eventAt.plusDays(parameter.getRedeemValidity()).withHour(23).withMinute(59).withSecond(59));
        initCoupon.setEffectAt(eventAt.with(LocalTime.MIN));
        initCoupon.setExpireAt(eventAt.plusDays(parameter.getValidity()).withHour(23).withMinute(59).withSecond(59));
        initCoupon.setOperator(ShiroUtils.getLoginName());
        initCoupon.setCreatedAt(nowTime);

        List<CandyCouponRuleBuildParam> couponRuleList = parameter.getCouponRuleList();
        List<CandyCouponRule> initCouponRuleList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(couponRuleList)) {
            couponRuleList.forEach(r -> {
                CandyCouponRule initCouponRule = new CandyCouponRule();
                initCouponRule.setCruleId(IDGenerator.nextTimeId2());
                initCouponRule.setCouponId(initCoupon.getCouponId());
                initCouponRule.setUseScope(r.getUseScope());
                initCouponRule.setBusiName(r.getBusiName());
                initCouponRule.setBusiId(r.getBusiId());
                initCouponRule.setState(1);

                initCouponRuleList.add(initCouponRule);
            });
        }

        CandyMgtCoupon initMgtCoupon = new CandyMgtCoupon();
        initMgtCoupon.setMcouponId(IDGenerator.nextMilliId());
        initMgtCoupon.setCouponId(initCoupon.getCouponId());
        initMgtCoupon.setState(0);
        initMgtCoupon.setEventAmt(parameter.getEventAmt());
        initMgtCoupon.setEventType(parameter.getEventType());
        initMgtCoupon.setEventLimit(parameter.getEventLimit());
        initMgtCoupon.setEventAt(eventAt);
        initMgtCoupon.setOperator(initCoupon.getOperator());
        initMgtCoupon.setCreatedAt(nowTime);

        return candyMgtCouponAdminService.saveMgtCouponInfo(initCoupon, initMgtCoupon, initCouponRuleList);
    }

    @Override
    @Transactional
    public boolean saveMgtCouponInfo(CandyCoupon initCoupon, CandyMgtCoupon initMgtCoupon, List<CandyCouponRule> initCouponRuleList) {
        int insertCt = candyCouponMapper.insert(initCoupon);
        insertCt += candyMgtCouponMapper.insert(initMgtCoupon);

        boolean saveBatch = candyCouponRuleAdminService.saveBatch(initCouponRuleList);

        if (insertCt < 2 || !saveBatch) {
            throw new LiquidnetServiceException();
        }

        switch (initCoupon.getExclusive()) {
            case 0:
                break;
            case 1:
                this.syncRdsForMemberRightsCouponProcessing(false, initCoupon, initMgtCoupon, initCouponRuleList);
                break;
        }

        return true;
    }

    @Override
    @Transactional
    public boolean updateMgtCouponInfo(CandyCoupon updateCoupon, CandyMgtCoupon updateMgtCoupon, List<CandyCouponRule> initCouponRuleList) {
        LambdaUpdateWrapper<CandyCoupon> couponLambdaUpdateWrapper = Wrappers.lambdaUpdate(CandyCoupon.class)
                .eq(CandyCoupon::getCouponId, updateCoupon.getCouponId())
                .eq(CandyCoupon::getState, 1)
                .eq(CandyCoupon::getExclusive, updateCoupon.getExclusive());
        int updateCt = candyCouponMapper.update(updateCoupon, couponLambdaUpdateWrapper);

        LambdaUpdateWrapper<CandyMgtCoupon> mgtCouponLambdaUpdateWrapper = Wrappers.lambdaUpdate(CandyMgtCoupon.class)
                .eq(CandyMgtCoupon::getMcouponId, updateMgtCoupon.getMcouponId())
                .eq(CandyMgtCoupon::getState, updateCoupon.getExclusive() == 1 ? 10 : 0);
        updateCt += candyMgtCouponMapper.update(updateMgtCoupon, mgtCouponLambdaUpdateWrapper);


        LambdaUpdateWrapper<CandyCouponRule> couponRuleLambdaUpdateWrapper = Wrappers.lambdaUpdate(CandyCouponRule.class)
                .eq(CandyCouponRule::getCouponId, updateCoupon.getCouponId())
                .eq(CandyCouponRule::getState, 1)
                .set(CandyCouponRule::getState, 2);
        candyCouponRuleAdminService.update(couponRuleLambdaUpdateWrapper);

        if (updateCt < 2 || !candyCouponRuleAdminService.saveBatch(initCouponRuleList)) {
            throw new LiquidnetServiceException();
        }

        switch (updateCoupon.getExclusive()) {
            case 0:
                break;
            case 1:
                this.syncRdsForMemberRightsCouponProcessing(true, updateCoupon, updateMgtCoupon, initCouponRuleList);
                break;
        }

        return true;
    }

    @Override
    public List<CandyMgtCouponInfoDto> listForMgtCouponInfoDto(CandyMgtCouponListParam listParam) {
        return candyMgtCouponMapper.selectMultiForMgtCouponInfoDto(listParam);
    }

    @Override
    public List<CandyMgtCouponMemberDto> listForMgtCouponMemberDto(List<String> mrightsIdList) {
        return candyMgtCouponMapper.selectMultiForMgtCouponMemberDto(mrightsIdList);
    }

    /* ----------------------------------------------------------------------------- */

    private List<AdamMemberRightsCouponRuleVo> copyFromCandyCouponRule(List<CandyCouponRule> couponRuleList) {
        List<AdamMemberRightsCouponRuleVo> memberRightsCouponRuleVoList = new ArrayList<>();
        couponRuleList.forEach(r -> {
            AdamMemberRightsCouponRuleVo memberRightsCouponRuleVo = AdamMemberRightsCouponRuleVo.getNew();
            memberRightsCouponRuleVo.setBusiId(r.getBusiId());
            memberRightsCouponRuleVo.setBusiName(r.getBusiName());
            memberRightsCouponRuleVo.setUseScope(r.getUseScope());

            memberRightsCouponRuleVoList.add(memberRightsCouponRuleVo);
        });
        return memberRightsCouponRuleVoList;
    }

    /**
     * 同步REDIS:用户端:购买会员详情页:权益列表:权益详情:专享券信息
     *
     * @param editing            true-编辑｜false-新增
     * @param updateCoupon       CandyCoupon
     * @param updateMgtCoupon    CandyCoupon
     * @param initCouponRuleList List<CandyCouponRule>
     */
    private void syncRdsForMemberRightsCouponProcessing(boolean editing, CandyCoupon updateCoupon, CandyMgtCoupon updateMgtCoupon, List<CandyCouponRule> initCouponRuleList) {
        List<AdamMemberRightsCouponRuleVo> memberRightsCouponRuleVoList = this.copyFromCandyCouponRule(initCouponRuleList);

        List<AdamMemberRightsCouponVo> memberRightsCouponVoList =
                (List<AdamMemberRightsCouponVo>) redisUtil.get(AdamRedisConst.INFO_MEMBER_RIGHTS_COUPON.concat(updateMgtCoupon.getMcouponId()));
        if (editing) {// 编辑操作
            memberRightsCouponVoList.removeIf(r -> r.getCouponId().equals(updateCoupon.getCouponId()));
        } else {// 新增操作
            if (CollectionUtils.isEmpty(memberRightsCouponVoList)) {
                memberRightsCouponVoList = new ArrayList<>();
            }
        }
        Integer eventAmt = updateMgtCoupon.getEventAmt();
        for (int i = 0; i < eventAmt; i++) {
            AdamMemberRightsCouponVo memberRightsCouponVo = AdamMemberRightsCouponVo.getNew();
            memberRightsCouponVo.setMrightsId(updateMgtCoupon.getMcouponId());
            memberRightsCouponVo.setCouponId(updateCoupon.getCouponId());
            memberRightsCouponVo.setBusiType(updateCoupon.getBusiType());
            memberRightsCouponVo.setCouType(updateCoupon.getCouType());
            memberRightsCouponVo.setTitle(updateCoupon.getTitle());
            memberRightsCouponVo.setLabel(updateCoupon.getLabel());
            memberRightsCouponVo.setNotice(updateCoupon.getNotice());
            memberRightsCouponVo.setValFace(updateCoupon.getValFace());
            memberRightsCouponVo.setValOver(updateCoupon.getValOver());
            memberRightsCouponVo.setValMinus(updateCoupon.getValMinus());
            memberRightsCouponVo.setUseRules(memberRightsCouponRuleVoList);

            memberRightsCouponVoList.add(memberRightsCouponVo);
        }
        redisUtil.set(AdamRedisConst.INFO_MEMBER_RIGHTS_COUPON.concat(updateMgtCoupon.getMcouponId()), memberRightsCouponVoList);
    }
}
