package com.xinelu.applet.service.patientcenter.impl;

import com.xinelu.applet.dto.nursingstationgoods.GoodsList;
import com.xinelu.applet.dto.nursingstationgoods.GoodsOrderStationDTO;
import com.xinelu.applet.dto.patientcenter.PatientCenterCouponDTO;
import com.xinelu.applet.mapper.nurseapplogin.NurseAppLoginMapper;
import com.xinelu.applet.mapper.nursingstationgoods.NursingStationGoodsMapper;
import com.xinelu.applet.mapper.patientcenter.PatientCenterMapper;
import com.xinelu.applet.service.patientcenter.PatientCenterService;
import com.xinelu.applet.vo.coupon.CouponVO;
import com.xinelu.applet.vo.patientcenter.PatientCenterCouponVO;
import com.xinelu.applet.vo.patientcenter.PatientSignInVO;
import com.xinelu.applet.vo.patientcenter.PatientSignInfoVO;
import com.xinelu.common.config.AppletChatConfig;
import com.xinelu.common.config.AppletPageConfig;
import com.xinelu.common.config.XinELuConfig;
import com.xinelu.common.constant.Constants;
import com.xinelu.common.core.domain.AjaxResult;
import com.xinelu.common.core.page.TableDataInfo;
import com.xinelu.common.enums.*;
import com.xinelu.common.exception.ServiceException;
import com.xinelu.common.utils.AppletChatUtil;
import com.xinelu.common.utils.PageServiceUtil;
import com.xinelu.common.utils.RedisDistributedLockUtils;
import com.xinelu.common.utils.bean.BeanUtils;
import com.xinelu.manage.domain.coupon.Coupon;
import com.xinelu.manage.domain.goodsAttributeDetails.GoodsAttributeDetails;
import com.xinelu.manage.domain.goodsOrder.GoodsOrder;
import com.xinelu.manage.domain.goodsOrderDetails.GoodsOrderDetails;
import com.xinelu.manage.domain.patientcouponreceive.PatientCouponReceive;
import com.xinelu.manage.domain.patientintegralchange.PatientIntegralChange;
import com.xinelu.manage.domain.patientsignininfo.PatientSignInInfo;
import com.xinelu.manage.domain.subscribemessagerecord.SubscribeMessageRecord;
import com.xinelu.manage.domain.systemsettingsinfo.SystemSettingsInfo;
import com.xinelu.manage.mapper.coupon.CouponMapper;
import com.xinelu.manage.mapper.goodsAttributeDetails.GoodsAttributeDetailsMapper;
import com.xinelu.manage.mapper.goodsOrder.GoodsOrderMapper;
import com.xinelu.manage.mapper.goodsOrderDetails.GoodsOrderDetailsMapper;
import com.xinelu.manage.mapper.patientcouponreceive.PatientCouponReceiveMapper;
import com.xinelu.manage.mapper.patientinfo.PatientInfoMapper;
import com.xinelu.manage.mapper.patientintegralchange.PatientIntegralChangeMapper;
import com.xinelu.manage.mapper.patientsignininfo.PatientSignInInfoMapper;
import com.xinelu.manage.mapper.subscribemessagerecord.SubscribeMessageRecordMapper;
import com.xinelu.manage.mapper.systemsettingsinfo.SystemSettingsInfoMapper;
import com.xinelu.manage.service.messagepush.MessagePushService;
import com.xinelu.manage.vo.patientcouponreceive.PatientCouponReceiveInfoVO;
import com.xinelu.manage.vo.patientinfo.PatientInfoVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;


/**
 * @Description 会员APP和小程序个人中心业务层实现类
 * @Author 纪寒
 * @Date 2023-02-24 14:45:35
 * @Version 1.0
 */
@Slf4j
@Service
public class PatientCenterServiceImpl implements PatientCenterService {
    @Resource
    private PatientCenterMapper patientCenterMapper;
    @Resource
    private SystemSettingsInfoMapper systemSettingsInfoMapper;
    @Resource
    private PatientSignInInfoMapper patientSignInInfoMapper;
    @Resource
    private PatientIntegralChangeMapper patientIntegralChangeMapper;
    @Resource
    private PatientInfoMapper patientInfoMapper;
    @Resource
    private AppletPageConfig appletPageConfig;
    @Resource
    private XinELuConfig xinYiLuConfig;
    @Resource
    private NurseAppLoginMapper nurseAppLoginMapper;
    @Resource
    private PageServiceUtil pageServiceUtil;
    @Resource
    private PatientCouponReceiveMapper patientCouponReceiveMapper;
    @Resource
    private NursingStationGoodsMapper nursingStationGoodsMapper;
    @Resource
    private RedisDistributedLockUtils redisDistributedLockUtils;
    @Resource
    private GoodsAttributeDetailsMapper goodsAttributeDetailsMapper;
    @Resource
    private GoodsOrderMapper goodsOrderMapper;
    @Resource
    private GoodsOrderDetailsMapper goodsOrderDetailsMapper;
    @Resource
    private CouponMapper couponMapper;
    @Resource
    private AppletChatConfig appletChatConfig;
    @Resource
    private SubscribeMessageRecordMapper subscribeMessageRecordMapper;
    @Resource
    private MessagePushService messagePushService;
    @Resource
    private AppletChatUtil appletChatUtil;
    /**
     * 用户第一次签到次数
     */
    private static final int FIRST_SIGN_COUNT = 1;

    /**
     * 获取小程序二维码接口失败标识
     */
    private static final String FAIL = "FAIL";

    /**
     * 会员app和微信小程序-签到方法
     *
     * @param patientId     会员用户id
     * @param signInChannel 签到来源，微信小程序、会员APP
     * @return 签到结果
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public AjaxResult patientSignIn(Long patientId, String signInChannel) {
        //确认用户是否是第一次签到
        PatientSignInVO patientSignInInfo = patientCenterMapper.getPatientSignInInfo(patientId, LocalDate.now());
        if (Objects.isNull(patientSignInInfo)) {
            return AjaxResult.error("当前用户信息不存在，无法进行签到，请联系管理员！");
        }
        if (Objects.nonNull(patientSignInInfo.getTotalSignInDays()) && patientSignInInfo.getTodaySignInCount() > 0) {
            return AjaxResult.error("您今天已经签到！");
        }
        boolean isFirstSignIn = Objects.isNull(patientSignInInfo.getSignInCount()) || patientSignInInfo.getSignInCount() == 0;
        if (Objects.isNull(patientSignInInfo.getTotalSignInDays()) && BooleanUtils.isTrue(isFirstSignIn)) {
            //当前用户第一次签到，记录签到信息
            patientCenterMapper.updateTotalSignInDays(patientId);
            this.setPatientSignInInfo(patientId, signInChannel);
            //第一次签到送积分以及记录积分变更记录
            this.insertGoodPatientIntegral(patientSignInInfo, FIRST_SIGN_COUNT, patientId, signInChannel);
            messagePushService.integralMessage(patientId, FIRST_SIGN_COUNT);
            return AjaxResult.success(FIRST_SIGN_COUNT);
        }
        //用户不是第一次签到，判断当前用户是否到达签到天数并送积分
        patientCenterMapper.updateTotalSignInDays(patientId);
        this.setPatientSignInInfo(patientId, signInChannel);
        AtomicInteger atomicInteger = new AtomicInteger(Objects.isNull(patientSignInInfo.getTotalSignInDays()) ? 0 : patientSignInInfo.getTotalSignInDays());
        int increment = atomicInteger.incrementAndGet();
        //新增账户积分以及记录积分变更记录
        this.insertGoodPatientIntegral(patientSignInInfo, increment, patientId, signInChannel);
        messagePushService.integralMessage(patientId, increment);
        return AjaxResult.success(increment);
    }

    /**
     * 个人中心优惠券
     *
     * @param patientCenterCouponVO 用户信息及优惠券状态
     * @return List<CouponVO>
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public List<CouponVO> selectCouponByUseStatus(PatientCenterCouponVO patientCenterCouponVO) {
        patientCenterCouponVO.setReceiveSource(CouponReceiveTypeEnum.NEW_PEOPLE_WELFARE.getInfo());
        List<String> useStatusList = Arrays.asList(CouponUseStatusEnum.USED.getInfo(), CouponUseStatusEnum.NOT_USED.getInfo(), CouponUseStatusEnum.EXPIRED.getInfo());
        patientCenterCouponVO.setUseStatusList(useStatusList);
        List<CouponVO> couponList = patientCenterMapper.selectCouponByUseStatus(patientCenterCouponVO);
        //筛查过期的优惠券
        for (CouponVO couponVO : couponList) {
            if (Objects.isNull(couponVO) || Objects.isNull(couponVO.getExpirationEndTime())) {
                continue;
            }
            if (LocalDateTime.now().isAfter(couponVO.getExpirationEndTime())) {
                PatientCouponReceive patientCouponReceive = new PatientCouponReceive();
                patientCouponReceive.setId(Objects.isNull(couponVO.getPatientCouponReceiveId()) ? 0 : couponVO.getPatientCouponReceiveId());
                patientCouponReceive.setUseStatus(CouponUseStatusEnum.EXPIRED.getInfo());
                int couponReceive = patientCouponReceiveMapper.updatePatientCouponReceive(patientCouponReceive);
                if (couponReceive < 0) {
                    throw new ServiceException("个人中心优惠券查询失败，请联系管理员！");
                }
                couponVO.setUseStatus(CouponUseStatusEnum.EXPIRED.getInfo());
            }
        }
        return couponList;
    }

    /**
     * 积分兑换 - 查询积分兑换商品
     *
     * @return AjaxResult
     */
    @Override
    public List<GoodsList> selectExchangeGoods() {
        //传入积分兑换标识、是否上架、商品买卖
        return patientCenterMapper.selectGoodsByExchangeFlag(CouponAndIntegralFlagEnum.CONVERTIBLE.getInfo(), WhetherShelfEnum.SHEL.getInfo(), GoodsPurposeEnum.BUSINESS.getInfo());
    }

    /**
     * 获取积分返回规则
     *
     * @param patientId 用户id
     * @return com.xinyilu.nurseapplet.domain.vo.patientcenter.PatientSignInfoVO
     **/
    @Override
    public PatientSignInfoVO selectPatientSignIn(Long patientId) {
        //查询积分签到规则和邀请好友规则
        List<String> ruleList = Arrays.asList(SettingsTypeEnum.INVITE_FRIENDS.getInfo(), SettingsTypeEnum.SIGN_IN_RULE.getInfo());
        Map<String, PatientSignInfoVO> ruleMap = patientCenterMapper.selectPatientSignIn(patientId, LocalDate.now(), ruleList).stream().filter(item -> StringUtils.isNotBlank(item.getSettingsType())).collect(Collectors.toMap(PatientSignInfoVO::getSettingsType, item -> item));
        PatientSignInfoVO vo = new PatientSignInfoVO();
        //获取累计签到规则信息
        PatientSignInfoVO signInfoVO = ruleMap.getOrDefault(SettingsTypeEnum.SIGN_IN_RULE.getInfo(), new PatientSignInfoVO());
        if (Objects.nonNull(signInfoVO) && Objects.nonNull(signInfoVO.getTotalSignInDays())) {
            vo.setTotalSignInDays(signInfoVO.getTotalSignInDays());
        } else {
            vo.setTotalSignInDays(0);
        }
        if (Objects.nonNull(signInfoVO) && Objects.nonNull(signInfoVO.getIntegralCount())) {
            vo.setSignInCount(signInfoVO.getIntegralCount());
        } else {
            vo.setSignInCount(0);
        }
        //获取邀请规则信息
        PatientSignInfoVO inviteVO = ruleMap.getOrDefault(SettingsTypeEnum.INVITE_FRIENDS.getInfo(), new PatientSignInfoVO());
        if (Objects.nonNull(inviteVO) && Objects.nonNull(inviteVO.getIntegralCount())) {
            vo.setInviteFriends(inviteVO.getIntegralCount());
        } else {
            vo.setInviteFriends(0);
        }
        //查询用户签到天数和账户积分信息
        PatientSignInfoVO patientSignInfo = patientCenterMapper.getPatientSignInfo(patientId, LocalDate.now());
        if (Objects.isNull(patientSignInfo)) {
            throw new ServiceException("当前用户信息不存在，获取积分信息失败！");
        }
        vo.setPatientSignInCount(Objects.isNull(patientSignInfo.getPatientSignInCount()) ? 0 : patientSignInfo.getPatientSignInCount());
        vo.setIntegral(Objects.isNull(patientSignInfo.getIntegral()) ? 0 : patientSignInfo.getIntegral());
        vo.setTodaySignInCount(Objects.isNull(patientSignInfo.getTodaySignInCount()) ? 0 : patientSignInfo.getTodaySignInCount());
        return vo;
    }

    /**
     * 微信小程序-邀请好友接口
     *
     * @param inviteId 邀请人id
     * @return 邀请码图片地址
     */
    @Override
    public AjaxResult inviteFriends(Long inviteId) {
        //获取微信小程序AccessToken的值
        PatientInfoVO patientInfo = patientInfoMapper.getPatientInfoById(inviteId);
        if (Objects.isNull(patientInfo)) {
            return AjaxResult.error("当前用户信息不存在，请联系管理员！");
        }
        if (StringUtils.isBlank(patientInfo.getPersonalWechatCodeUrl())) {
            String fileName = String.valueOf(System.nanoTime()) + inviteId + ".png";
            //小程序跳转路径
            String appletPageUrl = appletPageConfig.getPageUrl();
            //邀请人二维码存放路径
            String filePathWeChatCodeUrl = xinYiLuConfig.getPersonalWeChatCodeUrl();
            String appletCodePicture = appletChatUtil.createAppletCode(inviteId, false, fileName, appletPageUrl, filePathWeChatCodeUrl);
            if (StringUtils.isNotBlank(appletCodePicture) && StringUtils.equals(FAIL, appletCodePicture)) {
                //第一次调用获取小程序二维码信息失败，重新递归调用一次，第二次失败直接返回提示信息
                appletCodePicture = appletChatUtil.createAppletCode(inviteId, true, fileName, appletPageUrl, filePathWeChatCodeUrl);
                if (StringUtils.isNotBlank(appletCodePicture) && StringUtils.equals(FAIL, appletCodePicture)) {
                    return AjaxResult.error("获取小程序二维码信息失败，请联系管理员！");
                }
            }
            String pictureUrl = "";
            if (StringUtils.isNotBlank(appletCodePicture)) {
                pictureUrl = "/profile" + xinYiLuConfig.getPersonalWeChatCodeUrl() + "/" + inviteId + "/" + fileName;
                int updateCount = patientInfoMapper.updatePersonalWeChatCodeUrl(inviteId, pictureUrl);
                if (updateCount <= 0) {
                    throw new ServiceException("获取微信小程序二维码信息失败，请联系管理员！");
                }
            }
            return AjaxResult.success(pictureUrl);
        }
        //直接返回二维码图片信息
        return AjaxResult.success(patientInfo.getPersonalWechatCodeUrl());
    }

    /**
     * 新增积分兑换商品订单以及详细信息
     *
     * @param goodsOrder 商品订单
     * @return 结果
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public AjaxResult insertIntegralGoodsOrder(GoodsOrderStationDTO goodsOrder) {
        //判断当前会员信息是否存在
        PatientInfoVO patientInfo = patientInfoMapper.getPatientInfoById(goodsOrder.getPatientId());
        if (Objects.isNull(patientInfo)) {
            return AjaxResult.error("当前用户信息不存在，无法兑换！");
        }
        GoodsAttributeDetails goodsAttributeDetails = nursingStationGoodsMapper.selectGoodsAttributeDetailsGoodsStockById(goodsOrder.getGoodsAttributeDetailsId());
        //判断当前商品是否可兑换商品
        if (Objects.nonNull(goodsAttributeDetails) && CouponAndIntegralFlagEnum.NOT_CONVERTIBLE.getInfo().equals(goodsAttributeDetails.getIntegralExchangeFlag())) {
            return AjaxResult.error("当前商品非健康豆兑换商品，无法兑换！");
        }
        //判断积分兑换数值是否正确
        boolean integralExchangeSill = Objects.nonNull(goodsAttributeDetails) && Objects.isNull(goodsAttributeDetails.getIntegralExchangeSill());
        boolean equalIntegralExchangeSill = Objects.nonNull(goodsAttributeDetails) && !goodsOrder.getIntegralExchangeSill().equals(goodsAttributeDetails.getIntegralExchangeSill());
        if (BooleanUtils.isTrue(integralExchangeSill) || BooleanUtils.isTrue(equalIntegralExchangeSill)) {
            return AjaxResult.error("当前商品兑换需要使用的健康豆数量不正确，无法兑换！");
        }
        //判断积分兑换商品数目是否正确
        boolean integralExchangeCount = Objects.nonNull(goodsAttributeDetails) && Objects.isNull(goodsAttributeDetails.getIntegralExchangeCount());
        boolean equalIntegralExchangeCount = Objects.nonNull(goodsAttributeDetails) && !goodsOrder.getIntegralExchangeCount().equals(goodsAttributeDetails.getIntegralExchangeCount());
        if (BooleanUtils.isTrue(integralExchangeCount) || BooleanUtils.isTrue(equalIntegralExchangeCount)) {
            return AjaxResult.error("当前健康豆兑换商品的数量不正确，无法兑换！");
        }
        //判断库存是否充足
        if (Objects.isNull(goodsAttributeDetails.getGoodsStock()) || goodsAttributeDetails.getGoodsStock() == 0) {
            return AjaxResult.error("当前商品库存不足，无法兑换！");
        }
        //判读用户账户积分是否充足
        AtomicInteger patientIntegral = new AtomicInteger(Objects.isNull(patientInfo.getIntegral()) ? 0 : patientInfo.getIntegral());
        AtomicInteger exchangeIntegralSkill = new AtomicInteger(Objects.isNull(goodsOrder.getIntegralExchangeSill()) ? 0 : goodsOrder.getIntegralExchangeSill());
        if (patientIntegral.get() < exchangeIntegralSkill.get()) {
            return AjaxResult.error("当前用户的健康豆数目值不足，无法兑换！");
        }
        //判断商品库存数量是否满足兑换数量
        AtomicInteger goodsStock = new AtomicInteger(goodsAttributeDetails.getGoodsStock());
        AtomicInteger exchangeGoodsCount = new AtomicInteger(goodsOrder.getIntegralExchangeCount());
        if (goodsStock.get() < exchangeGoodsCount.get()) {
            return AjaxResult.error("当前商品库存不足，无法兑换！");
        }
        //生成兑换商品订单信息
        String goodOrderNo = com.xinelu.common.utils.StringUtils.fillZeroByPatientId(goodsOrder.getPatientId(), 5) + System.nanoTime();
        this.addExchangeGoodsOrderInfo(goodsOrder, patientInfo, exchangeIntegralSkill, exchangeGoodsCount, goodOrderNo);
        return AjaxResult.success(goodsOrderMapper.getGoodsOrderByOrderNo(goodOrderNo));
    }

    /**
     * 新增订阅微信小程序订阅消息记录
     *
     * @param subscribeMessageRecord 订阅微信小程序订阅消息记录
     * @return com.xinyilu.common.core.domain.AjaxResult
     **/
    @Transactional(rollbackFor = Exception.class)
    @Override
    public AjaxResult insertSubscribeMessageRecord(List<SubscribeMessageRecord> subscribeMessageRecord) {
        SubscribeMessageRecord messageRecord = new SubscribeMessageRecord();
        messageRecord.setPatientId(subscribeMessageRecord.get(0).getPatientId());
        messageRecord.setOpenid(subscribeMessageRecord.get(0).getOpenid());
        //查询数据库中的数据 并去重
        List<SubscribeMessageRecord> subscribeMessageRecords = subscribeMessageRecordMapper.selectSubscribeMessageRecordList(messageRecord);
        //前端穿过聊的数据并去重
        List<SubscribeMessageRecord> subscribeRecordVO = subscribeMessageRecord.stream().distinct().collect(Collectors.toList());
        //求出差集 要新增的
        List<SubscribeMessageRecord> messageRecordSubtract = new ArrayList<>(CollectionUtils.subtract(subscribeRecordVO, subscribeMessageRecords));
        //求出交集 要修改的
        List<SubscribeMessageRecord> messageRecordRetainAll = new ArrayList<>(CollectionUtils.intersection(subscribeRecordVO, subscribeMessageRecords));
        if (CollectionUtils.isNotEmpty(messageRecordRetainAll)) {
            for (SubscribeMessageRecord record : messageRecordRetainAll) {
                subscribeMessageRecordMapper.updateSubscribeMessageTemplateId(record.getOpenid(), record.getTemplateId(), record.getSubscribeStatus(), record.getPatientId());
            }
        }
        if (CollectionUtils.isNotEmpty(messageRecordSubtract)) {
            return AjaxResult.success();
        }
        //新增订阅消息表信息
        for (SubscribeMessageRecord record : messageRecordSubtract) {
            record.setAppletId(appletChatConfig.getAppletId());
            record.setSubscribeCount(1);
            record.setSubscribeTime(LocalDateTime.now());
            record.setSubscribeStatus(record.getSubscribeStatus());
            if (StringUtils.equals(appletChatConfig.getAppointOrderTemplateId(), record.getTemplateId())) {
                record.setMessageType(SubscribeMessageTypeEnum.APPOINT_ORDER_MESSAGE_PUSH.getInfo());
            }
            if (StringUtils.equals(appletChatConfig.getCouponReceiveTemplateId(), record.getTemplateId())) {
                record.setMessageType(SubscribeMessageTypeEnum.COUPON_RECEIVE_MESSAGE_PUSH.getInfo());
            }
            if (StringUtils.equals(appletChatConfig.getGoodsOrderTemplateId(), record.getTemplateId())) {
                record.setMessageType(SubscribeMessageTypeEnum.GOODS_ORDER_MESSAGE_PUSH.getInfo());
            }
        }
        int insertRecord = subscribeMessageRecordMapper.insertSubscribeMessageRecordList(messageRecordSubtract);
        if (insertRecord <= 0) {
            return AjaxResult.error("新增订阅消息失败，请联系管理员！");
        }
        return AjaxResult.success();
    }

    /**
     * 新人福利优惠券
     *
     * @param patientCenterCouponDTO 用户信息及优惠券状态
     * @return List<CouponVO>
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public TableDataInfo getCouponByUseStatus(PatientCenterCouponDTO patientCenterCouponDTO) {
        //用户无登录情况下
        if (Objects.isNull(patientCenterCouponDTO.getPatientId())) {
            pageServiceUtil.startPage();
            List<CouponVO> couponNewPeople = patientCenterMapper.getCouponNewPeople(CouponReceiveTypeEnum.NEW_PEOPLE_WELFARE.getInfo());
            return pageServiceUtil.getDataTable(couponNewPeople);
        }
        // 根据传过来的人员id去查询会员表中的完善标识字段
        Integer loginFlag = nurseAppLoginMapper.getLoginFlagByPatientId(patientCenterCouponDTO.getPatientId());
        patientCenterCouponDTO.setReceiveType(CouponReceiveTypeEnum.NEW_PEOPLE_WELFARE.getInfo());
        //去判断完善标识是否完善 如果没有完善就是新人 否则就是注册过的
        if (Objects.isNull(loginFlag)) {
            pageServiceUtil.startPage();
            List<CouponVO> couponNewPeople = patientCenterMapper.getCouponNewPeople(CouponReceiveTypeEnum.NEW_PEOPLE_WELFARE.getInfo());
            return pageServiceUtil.getDataTable(couponNewPeople);
        }
        pageServiceUtil.startPage();
        List<CouponVO> couponList = patientCenterMapper.getCouponByUseStatus(patientCenterCouponDTO);
        //筛查过期的优惠券
        for (CouponVO couponVO : couponList) {
            if (Objects.isNull(couponVO) || Objects.isNull(couponVO.getExpirationEndTime())) {
                continue;
            }
            if (LocalDateTime.now().isAfter(couponVO.getExpirationEndTime())) {
                PatientCouponReceive patientCouponReceive = new PatientCouponReceive();
                patientCouponReceive.setId(Objects.isNull(couponVO.getPatientCouponReceiveId()) ? 0 : couponVO.getPatientCouponReceiveId());
                patientCouponReceive.setUseStatus(CouponUseStatusEnum.EXPIRED.getInfo());
                patientCouponReceiveMapper.updatePatientCouponReceive(patientCouponReceive);
                couponVO.setUseStatus(CouponUseStatusEnum.EXPIRED.getInfo());
            }
        }
        return pageServiceUtil.getDataTable(couponList);
    }

    /**
     * 优惠券领取
     *
     * @param patientId 用户id
     * @param couponId  优惠券id
     * @return AjaxResult
     */
    @Override
    public AjaxResult insertCouponReceive(Long patientId, Long couponId) {
        PatientInfoVO patientInfo = patientInfoMapper.getPatientInfoById(patientId);
        if (Objects.isNull(patientInfo)) {
            return AjaxResult.error("用户不存在，无法领取！");
        }
        PatientCouponReceiveInfoVO patientCouponReceive = patientCouponReceiveMapper.selectPatientCouponReceive(patientId, couponId);
        if (Objects.nonNull(patientCouponReceive)) {
            if (StringUtils.isNotBlank(patientCouponReceive.getUseStatus()) && !CouponUseStatusEnum.WAIT_RECEIVE.getInfo().equals(patientCouponReceive.getUseStatus())) {
                return AjaxResult.error("该优惠券已领取！");
            }
            patientCouponReceive.setExpirationStartTime(LocalDateTime.now());
            patientCouponReceive.setExpirationEndTime(LocalDate.now().plusDays(patientCouponReceive.getCouponReductionDays()).atTime(23, 59, 59));
            patientCouponReceive.setReceiveTime(LocalDateTime.now());
            patientCouponReceive.setUseStatus(CouponUseStatusEnum.NOT_USED.getInfo());
            patientCouponReceive.setUpdateTime(LocalDateTime.now());
            patientCouponReceive.setCouponType(CouponTypeEnum.FULL_REDUCTION_COUPON.getInfo());
            patientCouponReceiveMapper.updatePatientCouponReceive(patientCouponReceive);
            return AjaxResult.success();
        }
        //组装优惠券信息 并发送订阅消息
        this.setCouponReceive(patientId, couponId);
        return AjaxResult.success();
    }


    /**
     * 生成签到信息
     *
     * @param patientId     用户id
     * @param signInChannel 签到渠道，微信小程序、手机APP
     */
    private void setPatientSignInInfo(Long patientId, String signInChannel) {
        PatientSignInInfo signInInfo = new PatientSignInInfo();
        signInInfo.setPatientId(patientId);
        signInInfo.setSignInChannel(signInChannel);
        signInInfo.setSignInTime(LocalDate.now());
        signInInfo.setCreateTime(LocalDateTime.now());
        int insertCount = patientSignInInfoMapper.insertPatientSignInInfo(signInInfo);
        if (insertCount <= 0) {
            log.error("生成签到记录表信息失败，签到信息：{}", signInInfo);
            throw new ServiceException("签到失败，请联系管理员！");
        }
    }

    /**
     * 生成签到信息
     *
     * @param patientId        用户id
     * @param signInChannel    签到渠道，微信小程序、手机APP
     * @param originalIntegral 原始账户积分
     * @param changeIntegral   赠送变更积分
     */
    private void setPatientIntegral(Long patientId, String signInChannel, int originalIntegral, int changeIntegral) {
        PatientIntegralChange integralChange = new PatientIntegralChange();
        integralChange.setPatientId(patientId);
        integralChange.setOriginalIntegral(originalIntegral);
        integralChange.setChangeIntegral(changeIntegral);
        integralChange.setChangeTime(LocalDateTime.now());
        integralChange.setChangeType(IntegralChangeType.SIGN_IN.getInfo());
        integralChange.setChangeRemark("签到赠送积分");
        integralChange.setChangeIntegralChannel(signInChannel);
        integralChange.setCreateTime(LocalDateTime.now());
        int insertCount = patientIntegralChangeMapper.insertPatientIntegralChange(integralChange);
        if (insertCount <= 0) {
            log.error("用户签到-生成积分变更记录表信息失败，积分变更信息：{}", integralChange);
            throw new ServiceException("签到失败，请联系管理员！");
        }
    }


    /**
     * 新增商品订单主表信息减积分数与库存
     *
     * @param goodsOrder            前端穿过来的订单数据
     * @param patientInfo           数据库查出的会员信息
     * @param exchangeIntegralSkill 前端传的商品兑换数值
     * @param exchangeGoodsCount    前端传的兑换商品积分数量
     */
    private void addExchangeGoodsOrderInfo(GoodsOrderStationDTO goodsOrder, PatientInfoVO patientInfo, AtomicInteger exchangeIntegralSkill, AtomicInteger exchangeGoodsCount, String goodOrderNo) {
        GoodsOrder good = new GoodsOrder();
        BeanUtils.copyBeanProp(good, goodsOrder);
        good.setPatientId(goodsOrder.getPatientId());
        good.setOrderNo(goodOrderNo);
        good.setOrderStatus(GooodsOrderStatusEnum.WAIT_RECEIVED_GOODS.getInfo());
        good.setRemark(com.xinelu.common.utils.StringUtils.isBlank(goodsOrder.getRemark()) ? "" : goodsOrder.getRemark());
        good.setOrderTime(LocalDateTime.now());
        good.setDelFlag(0);
        good.setTotalPrice(BigDecimal.ZERO);
        good.setOrderType(OrderTypeEnum.INTEGRAL_EXCHANGE.getInfo());
        good.setCreateTime(LocalDateTime.now());
        good.setNurseStationId(Objects.isNull(goodsOrder.getNurseStationId()) ? null : goodsOrder.getNurseStationId());
        good.setBuySource(Objects.nonNull(good.getNurseStationId()) ? BuySourceEnum.NURSE_STATION.getInfo() : BuySourceEnum.SHOPPING_MALL.getInfo());
        good.setOriginalTotalPrice(BigDecimal.ZERO);
        int stationGoodsOrder = goodsOrderMapper.insertGoodsOrder(good);
        if (stationGoodsOrder <= 0) {
            throw new ServiceException("商品订单新增信息失败，请联系管理员！");
        }
        //新增商品订单明细表信息
        GoodsOrderDetails goodsOrderDetails = new GoodsOrderDetails();
        BeanUtils.copyBeanProp(goodsOrderDetails, goodsOrder);
        goodsOrderDetails.setGoodsOrderId(good.getId());
        goodsOrderDetails.setOrderNo(goodOrderNo);
        goodsOrderDetails.setDelFlag(0);
        goodsOrderDetails.setTotalPrice(BigDecimal.ZERO);
        goodsOrderDetails.setCreateTime(LocalDateTime.now());
        goodsOrderDetails.setIntegralExchangeSill(goodsOrder.getIntegralExchangeSill());
        goodsOrderDetails.setIntegralExchangeCount(goodsOrder.getIntegralExchangeCount());
        int orderDetails = goodsOrderDetailsMapper.insertGoodsOrderDetails(goodsOrderDetails);
        if (orderDetails <= 0) {
            throw new ServiceException("商品订单明细新增信息失败，请联系管理员！");
        }
        //减少库存数量
        String goodsStockKey = Constants.BUY_GOODS_REDUCE_STOCK_KEY + goodOrderNo + "_" + goodsOrderDetails.getId();
        boolean tryLock = redisDistributedLockUtils.tryLock(goodsStockKey, 5);
        if (!tryLock) {
            log.info("商品订单获取Redis锁失败，订单编号 =====> {}", goodOrderNo);
            throw new ServiceException("减少库存信息失败，请联系管理员！");
        }
        try {
            //减少会员账户积分数
            patientInfoMapper.reducePatientIntegralCount(patientInfo.getId(), exchangeIntegralSkill.get());
            //减少库存数量
            goodsAttributeDetailsMapper.reduceGoodsStockCount(goodsOrder.getGoodsAttributeDetailsId(), exchangeGoodsCount.get());
            //会员积分变更记录
            this.setGoodPatientIntegral(patientInfo, exchangeIntegralSkill, good);
        } catch (Exception e) {
            log.error("减少库存与会员积分信息失败，失败原因为 ====> {}", e.getMessage());
            throw new ServiceException(e.getMessage());
        } finally {
            redisDistributedLockUtils.unlock(goodsStockKey);
        }
    }


    /**
     * 记录商品兑换积分变更信息
     *
     * @param patientInfo           会员信息
     * @param exchangeIntegralSkill 前端传的购买商品积分数量
     * @param good                  商品信息
     **/
    private void setGoodPatientIntegral(PatientInfoVO patientInfo, AtomicInteger exchangeIntegralSkill, GoodsOrder good) {
        PatientIntegralChange patientIntegralChange = new PatientIntegralChange();
        patientIntegralChange.setPatientId(patientInfo.getId());
        patientIntegralChange.setOriginalIntegral(patientInfo.getIntegral());
        patientIntegralChange.setChangeIntegral(exchangeIntegralSkill.get());
        patientIntegralChange.setChangeTime(LocalDateTime.now());
        patientIntegralChange.setChangeType(IntegralChangeType.COMMODITY_EXCHANGE.getInfo());
        patientIntegralChange.setChangeRemark("商品兑换扣减积分");
        patientIntegralChange.setChangeIntegralChannel(good.getOrderChannel());
        patientIntegralChange.setCreateTime(LocalDateTime.now());
        int integralChange = patientIntegralChangeMapper.insertPatientIntegralChange(patientIntegralChange);
        if (integralChange <= 0) {
            log.error("积分兑换商品-生成积分变更记录表信息失败，积分变更信息：{}", integralChange);
            throw new ServiceException("兑换商品失败，请联系管理员！");
        }
    }

    /**
     * 签到送积分-记录积分信息
     *
     * @param patientSignInInfo 会员
     * @param increment         签到天数
     * @param patientId         会员id
     * @param signInChannel     亲到方式
     */
    private void insertGoodPatientIntegral(PatientSignInVO patientSignInInfo, int increment, Long patientId, String signInChannel) {
        SystemSettingsInfo settingsInfo = systemSettingsInfoMapper.getSystemSettingsInfoByType(SettingsTypeEnum.SIGN_IN_RULE.getInfo());
        if (Objects.nonNull(settingsInfo) && Objects.nonNull(settingsInfo.getTotalSignInDays()) && increment >= settingsInfo.getTotalSignInDays()) {
            //赠送积分
            int originalIntegral = Objects.isNull(patientSignInInfo.getIntegral()) ? 0 : patientSignInInfo.getIntegral();
            int changeIntegral = Objects.isNull(settingsInfo.getIntegralCount()) ? 0 : settingsInfo.getIntegralCount();
            patientCenterMapper.updatePatientIntegral(patientId, changeIntegral);
            this.setPatientIntegral(patientId, signInChannel, originalIntegral, changeIntegral);
            //将用户表的签到天数清零
            patientCenterMapper.clearTotalSignInDays(patientId);
        }
    }


    /**
     * 组装优惠券信息 并发送订阅消息
     *
     * @param patientId 会员id
     * @param couponId  优惠券id
     **/
    private void setCouponReceive(Long patientId, Long couponId) {
        //组装优惠券信息
        Coupon couponInfo = couponMapper.selectCouponById(couponId);
        PatientCouponReceive couponReceive = new PatientCouponReceive();
        couponReceive.setPatientId(patientId);
        couponReceive.setCouponId(couponId);
        couponReceive.setReceiveSource(CouponReceiveTypeEnum.NEW_PEOPLE_WELFARE.getInfo());
        couponReceive.setExpirationStartTime(LocalDateTime.now());
        couponReceive.setExpirationEndTime(LocalDate.now().plusDays(couponInfo.getCouponReductionDays()).atTime(23, 59, 59));
        couponReceive.setReceiveTime(LocalDateTime.now());
        couponReceive.setCreateTime(LocalDateTime.now());
        couponReceive.setCouponTitle(com.xinelu.common.utils.StringUtils.isBlank(couponInfo.getCouponTitle()) ? "" : couponInfo.getCouponTitle());
        couponReceive.setCouponPrice(Objects.isNull(couponInfo.getCouponPrice()) ? BigDecimal.ZERO : couponInfo.getCouponPrice());
        couponReceive.setCouponConsumePrice(Objects.isNull(couponInfo.getCouponConsumePrice()) ? BigDecimal.ZERO : couponInfo.getCouponConsumePrice());
        couponReceive.setCouponDescription(com.xinelu.common.utils.StringUtils.isBlank(couponInfo.getCouponDescription()) ? "" : couponInfo.getCouponDescription());
        couponReceive.setUseStatus(CouponUseStatusEnum.NOT_USED.getInfo());
        patientCouponReceiveMapper.insertPatientCouponReceive(couponReceive);
    }
}
