package com.czg.service.market.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.czg.account.dto.QueryReceiveDto;
import com.czg.account.entity.ShopInfo;
import com.czg.account.entity.ShopUser;
import com.czg.account.entity.UserInfo;
import com.czg.account.service.ShopInfoService;
import com.czg.account.service.ShopUserService;
import com.czg.account.service.UserInfoService;
import com.czg.account.vo.CouponReceiveVo;
import com.czg.account.vo.UserCouponVo;
import com.czg.constant.MarketConstants;
import com.czg.exception.CzgException;
import com.czg.market.dto.*;
import com.czg.market.entity.MkShopCouponRecord;
import com.czg.market.entity.ShopCoupon;
import com.czg.market.entity.SmsPushEventUser;
import com.czg.market.service.MkShopCouponRecordService;
import com.czg.market.vo.CouponRecordCountVO;
import com.czg.market.vo.UserCouponVO;
import com.czg.service.market.mapper.MkShopCouponRecordMapper;
import com.czg.service.market.mapper.ShopCouponMapper;
import com.czg.utils.AssertUtil;
import com.czg.utils.CzgStrUtils;
import com.czg.utils.PageUtil;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/**
 * 优惠券发放记录表 服务层实现。
 *
 * @author ww
 * @since 2025-09-13
 */
@Slf4j
@DubboService
public class MkShopCouponRecordServiceImpl extends ServiceImpl<MkShopCouponRecordMapper, MkShopCouponRecord> implements MkShopCouponRecordService {


    @DubboReference
    private UserInfoService userInfoService;
    @DubboReference
    private ShopInfoService shopInfoService;
    @DubboReference
    private ShopUserService shopUserService;
    @Resource
    private ShopCouponMapper couponService;

    private static final List<String> TARGET_KEY = Arrays.asList("消费赠券", "充值赠券", "管理员赠送", "兑换码兑换", "群聊发放", "生日赠券",
            "购买会员赠券", "短信发放", "公众号发放", "用户弹窗领取", "积分兑换", "参与分享获得", "邀请获得");

    private static final Map<String, String> SOURCE_TO_CATEGORY = Map.ofEntries(
            Map.entry("用户弹窗领取", "用户领取"),
            Map.entry("兑换码兑换", "用户领取"),
            Map.entry("积分兑换", "用户领取"),
            Map.entry("参与分享获得", "分享获得"),
            Map.entry("邀请获得", "分享获得"),
            Map.entry("群聊发放", "群聊发放"),
            Map.entry("短信发放", "推广发放"),
            Map.entry("公众号发放", "推广发放"),
            Map.entry("管理员赠送", "管理员赠送"),
            Map.entry("消费赠券", "系统发送"),
            Map.entry("充值赠券", "系统发送"),
            Map.entry("生日赠券", "系统发送"),
            Map.entry("购买会员赠券", "系统发送")
    );

    private static final Map<String, Long> RESULT_COUNT_MAP = Map.ofEntries(
            Map.entry("用户领取", 0L),
            Map.entry("分享获得", 0L),
            Map.entry("群聊发放", 0L),
            Map.entry("推广发放", 0L),
            Map.entry("管理员赠送", 0L),
            Map.entry("系统发送", 0L)
    );

    //"积分兑换", "用户领取"

    @Override
    public List<CouponReceiveVo> queryReceive(QueryReceiveDto param) {
        return getMapper().queryReceive(param);
    }

    @Override
    public List<UserCouponVO> findByUser(String name, List<Long> shopUserIds, Integer status, Long shopId) {
        return getMapper().findCouponVOByUser(name, shopUserIds, status, shopId);
    }

    @Override
    public List<UserCouponVo> queryByVipIdAndShopId(Long shopId, Long shopUserId, Integer type, Integer isFood) {
        return getMapper().queryByVipIdAndShopId(shopId, shopUserId, type, isFood);
    }


    @Override
    public Map<String, Object> getRecord(MkShopCouponRecordDTO mkShopCouponRecordDTO, String startTime, String endTime) {
        AssertUtil.isNull(mkShopCouponRecordDTO.getCouponId(), "优惠券Id不能为空");
        ShopCoupon coupon = couponService.selectOneById(mkShopCouponRecordDTO.getCouponId());
        AssertUtil.isNull(coupon, "优惠券不存在");
        QueryWrapper recordQueryWrapper = new QueryWrapper();
        if (coupon.getSyncId() != null) {
            recordQueryWrapper.and(q -> {
                q.eq(MkShopCouponRecord::getCouponId, coupon.getId()).or(q1 -> {
                    q1.eq(MkShopCouponRecord::getCouponSyncId, coupon.getSyncId());
                });
            });
        } else {
            recordQueryWrapper.and(q -> {
                q.eq(MkShopCouponRecord::getCouponId, coupon.getId()).or(q1 -> {
                    q1.eq(MkShopCouponRecord::getCouponSyncId, coupon.getId());
                });
            });
        }
        recordQueryWrapper.eq(MkShopCouponRecord::getShopId, mkShopCouponRecordDTO.getShopId())
                .eq(MkShopCouponRecord::getIsDel, 0)
                .eq(MkShopCouponRecord::getStatus, mkShopCouponRecordDTO.getStatus())
                .eq(MkShopCouponRecord::getSource, CzgStrUtils.getStrOrNull(mkShopCouponRecordDTO.getSource()))
                .orderBy(MkShopCouponRecord::getCreateTime).desc();
        if (StrUtil.isNotBlank(startTime) && StrUtil.isNotBlank(endTime)) {
            recordQueryWrapper.between(MkShopCouponRecord::getCreateTime, startTime, endTime);
        }
        if (mkShopCouponRecordDTO.getUserId() != null) {
            recordQueryWrapper.eq(MkShopCouponRecord::getUserId, mkShopCouponRecordDTO.getUserId());
        }
        Page<MkShopCouponRecordDTO> recordPage = pageAs(PageUtil.buildPage(), recordQueryWrapper, MkShopCouponRecordDTO.class);
        if (mkShopCouponRecordDTO.getUserId() != null) {
            UserInfo userInfo = userInfoService.getById(mkShopCouponRecordDTO.getUserId());
            for (MkShopCouponRecordDTO record : recordPage.getRecords()) {
                record.setHeadImg(userInfo.getHeadImg());
                record.setNickName(userInfo.getNickName());
            }
        } else {
            for (MkShopCouponRecordDTO record : recordPage.getRecords()) {
                UserInfo userInfo = userInfoService.getById(record.getUserId());
                record.setHeadImg(userInfo.getHeadImg());
                record.setNickName(userInfo.getNickName());
            }
        }
        Map<String, Object> resultmap = BeanUtil.beanToMap(recordPage);
        List<CouponRecordCountVO> recordCountVO = getMapper().countRecordBySource(mkShopCouponRecordDTO.getCouponId(), mkShopCouponRecordDTO.getUserId(),
                mkShopCouponRecordDTO.getStatus(), mkShopCouponRecordDTO.getSource(), startTime, endTime);
        Map<String, Long> tempMap = recordCountVO.stream()
                .collect(Collectors.toMap(
                        CouponRecordCountVO::getSourceType,
                        CouponRecordCountVO::getCount
                ));
        Map<String, Long> categoryMap = TARGET_KEY.stream()
                .collect(Collectors.toMap(
                        key -> key,
                        key -> tempMap.getOrDefault(key, 0L)
                ));
        resultmap.put("categoryMap", categoryMap);
        Map<String, Long> resultCountMap = new HashMap<>(RESULT_COUNT_MAP);

        if (CollUtil.isNotEmpty(recordCountVO)) {
            for (CouponRecordCountVO record : recordCountVO) {
                String sourceName = record.getSourceType();
                Long count = record.getCount();

                String category = SOURCE_TO_CATEGORY.get(sourceName);
                if (category != null) {
                    resultCountMap.put(category, resultCountMap.get(category) + count);
                }
            }
        }
        resultmap.put("categoryMap", categoryMap);
        resultmap.put("resultCountMap", resultCountMap);
        return resultmap;
    }

    @Override
    public Page<MkShopCouponRecordDTO> getConsumerRecord(MkShopCouponRecordDTO mkShopCouponRecordDTO, String startTime, String endTime) {
        QueryWrapper recordQueryWrapper = new QueryWrapper();
        AssertUtil.isNull(mkShopCouponRecordDTO.getSourceId(), "消费赠券Id不能为空");
        recordQueryWrapper.eq(MkShopCouponRecord::getShopId, mkShopCouponRecordDTO.getShopId())
                .eq(MkShopCouponRecord::getIsDel, 0)
                .eq(MkShopCouponRecord::getStatus, mkShopCouponRecordDTO.getStatus())
                .eq(MkShopCouponRecord::getSource, "消费赠券")
                .eq(MkShopCouponRecord::getSourceId, mkShopCouponRecordDTO.getSourceId())
                .orderBy(MkShopCouponRecord::getCreateTime).desc();
        if (StrUtil.isNotBlank(startTime) && StrUtil.isNotBlank(endTime)) {
            recordQueryWrapper.between(MkShopCouponRecord::getCreateTime, startTime, endTime);
        }
        if (mkShopCouponRecordDTO.getUserId() != null) {
            recordQueryWrapper.eq(MkShopCouponRecord::getUserId, mkShopCouponRecordDTO.getUserId());
        }
        Page<MkShopCouponRecordDTO> recordPage = pageAs(PageUtil.buildPage(), recordQueryWrapper, MkShopCouponRecordDTO.class);
        if (mkShopCouponRecordDTO.getUserId() != null) {
            UserInfo userInfo = userInfoService.getById(mkShopCouponRecordDTO.getUserId());
            for (MkShopCouponRecordDTO record : recordPage.getRecords()) {
                record.setHeadImg(userInfo.getHeadImg());
                record.setNickName(userInfo.getNickName());
            }
        } else {
            for (MkShopCouponRecordDTO record : recordPage.getRecords()) {
                UserInfo userInfo = userInfoService.getById(record.getUserId());
                record.setHeadImg(userInfo.getHeadImg());
                record.setNickName(userInfo.getNickName());
            }
        }
        return recordPage;
    }

    @Override
    public Page<MkShopCouponRecordDTO> getRecordByShopUser(MkShopCouponRecordDTO mkShopCouponRecordDTO, String startTime, String endTime) {
        AssertUtil.isNull(mkShopCouponRecordDTO.getShopUserId(), "店铺用户ID不能为空");
        QueryWrapper recordQueryWrapper = new QueryWrapper();
        recordQueryWrapper.eq(MkShopCouponRecord::getShopId, mkShopCouponRecordDTO.getShopId())
                .eq(MkShopCouponRecord::getIsDel, 0)
                .eq(MkShopCouponRecord::getStatus, mkShopCouponRecordDTO.getStatus())
                .eq(MkShopCouponRecord::getShopUserId, mkShopCouponRecordDTO.getShopUserId())
                .orderBy(MkShopCouponRecord::getCreateTime).desc();
        if (StrUtil.isNotBlank(startTime) && StrUtil.isNotBlank(endTime)) {
            recordQueryWrapper.between(MkShopCouponRecord::getCreateTime, startTime, endTime);
        }
        Page<MkShopCouponRecordDTO> recordPage = pageAs(PageUtil.buildPage(), recordQueryWrapper, MkShopCouponRecordDTO.class);
        if (mkShopCouponRecordDTO.getUserId() != null) {
            ShopUser shopUser = shopUserService.getById(mkShopCouponRecordDTO.getShopUserId());
            for (MkShopCouponRecordDTO record : recordPage.getRecords()) {
                record.setHeadImg(shopUser.getHeadImg());
                record.setNickName(shopUser.getNickName());
            }
        }
        return recordPage;
    }

    @Override
    public void acGrantCoupon(AcPushEventDTO param) {
        //发放优惠券
        CompletableFuture.runAsync(() -> {
            try {
                SmsPushEventUser smsPushEventUser = param.getPushEventUser();
                List<ShopUser> userList;
                if (param.getUserType() == 1) {
                    smsPushEventUser = new SmsPushEventUser();
                    smsPushEventUser.setShopId(param.getShopId());
                    smsPushEventUser.setIsAll(1);
                }
                userList = shopUserService.getPushEventUserList(smsPushEventUser);
                // 2. 将JSON字符串解析为JSONArray
                JSONArray couponArray = JSON.parseArray(param.getCoupon());

                // 3. 遍历JSONArray，逐个获取JSONObject的字段值
                for (int i = 0; i < couponArray.size(); i++) {
                    // 获取单个优惠券的JSONObject对象
                    JSONObject couponObj = couponArray.getJSONObject(i);
                    // 通过键名获取对应值（需注意字段类型，按需转换）
                    Long id = couponObj.getLong("id");
                    Integer num = couponObj.getInteger("num");
                    MkShopCouponGiftDTO giftDTO = new MkShopCouponGiftDTO();
                    giftDTO.setShopId(param.getShopId());
                    giftDTO.setSourceId(param.getId());
                    giftDTO.setCouponId(id);
                    giftDTO.setSource("公众号发放");
                    batchReceiveCoupon(giftDTO, num, userList);
                }
            } catch (Exception e) {
                log.error("异步发放优惠券失败", e);
            }
        });
    }

    @Override
    public void smsGrantCoupon(SmsPushEventDTO param) {
        //发放优惠券
        CompletableFuture.runAsync(() -> {
            try {
                SmsPushEventUser smsPushEventUser = param.getSmsPushEventUser();
                List<ShopUser> userList;
                if (param.getUserType() == 1) {
                    smsPushEventUser = new SmsPushEventUser();
                    smsPushEventUser.setShopId(param.getShopId());
                    smsPushEventUser.setIsAll(1);
                }
                userList = shopUserService.getPushEventUserList(smsPushEventUser);
                // 2. 将JSON字符串解析为JSONArray
                JSONArray couponArray = JSON.parseArray(param.getCoupon());

                // 3. 遍历JSONArray，逐个获取JSONObject的字段值
                for (int i = 0; i < couponArray.size(); i++) {
                    // 获取单个优惠券的JSONObject对象
                    JSONObject couponObj = couponArray.getJSONObject(i);
                    // 通过键名获取对应值（需注意字段类型，按需转换）
                    Long id = couponObj.getLong("id");
                    Integer num = couponObj.getInteger("num");
                    MkShopCouponGiftDTO giftDTO = new MkShopCouponGiftDTO();
                    giftDTO.setShopId(param.getShopId());
                    giftDTO.setSourceId(param.getId());
                    giftDTO.setCouponId(id);
                    giftDTO.setSource("短信发放");
                    batchReceiveCoupon(giftDTO, num, userList);
                }
            } catch (Exception e) {
                log.error("异步发放优惠券失败", e);
            }
        });
    }

    @Override
    @Transactional
    public void receiveCoupon(MkShopCouponGiftDTO giftDTO, Integer number, boolean isLimit) {
        if (number == null || number <= 0) {
            throw new CzgException("发放数量不能小于0");
        }
        AssertUtil.isNull(giftDTO.getShopId(), "店铺id不能为空");
        AssertUtil.isNull(giftDTO.getShopUserId(), "店铺用户id不能为空");
        AssertUtil.isNull(giftDTO.getCouponId(), "优惠券id不能为空");
        AssertUtil.isNull(giftDTO.getSourceId(), "来源活动id不能为空");
        AssertUtil.isBlank(giftDTO.getSource(), "来源描述不能为空");
        ShopInfo shopInfo = shopInfoService.getById(giftDTO.getShopId());
        AssertUtil.isNull(shopInfo, "店铺不存在");
        ShopUser shopUser = shopUserService.getById(giftDTO.getShopUserId());
        AssertUtil.isNull(shopUser, "店铺用户不存在");
        ShopCoupon coupon = couponService.selectOneById(giftDTO.getCouponId());
        AssertUtil.isNull(coupon, "优惠券不存在");
        AssertUtil.isNotEqual(coupon.getIsDel(), 0, "优惠券状态异常");
        AssertUtil.isNull(coupon.getShopId(), "优惠券店铺不存在");
        AssertUtil.isNotEqual(coupon.getShopId(), giftDTO.getShopId(), "优惠券店铺与发放店铺不一致");
        AssertUtil.isNotEqual(coupon.getStatus(), 1, "优惠券已失效");
        if (isLimit) {
            if (coupon.getGiveNum() >= 0 && coupon.getLeftNum() < number) {
                throw new CzgException("优惠券库存不足");
            }
            //查询已领取张数
            long count = this.queryChain()
                    .eq(MkShopCouponRecord::getShopUserId, shopUser.getId())
                    .eq(MkShopCouponRecord::getCouponId, giftDTO.getCouponId()).count();
            if (coupon.getGetLimit() >= 0 && count >= coupon.getGetLimit()) {
                throw new CzgException("已达到领取限制，不可领取");
            }
        }
        coupon.setGiftNum(coupon.getGiftNum() + number);
        if (coupon.getGiveNum() != MarketConstants.Num.NOT_LIMIT && isLimit) {
            coupon.setLeftNum(coupon.getLeftNum() - number);
        }
        String couponJson = JSONObject.toJSONString(coupon);
        LocalDateTime start = LocalDateTime.now().with(LocalTime.MIN);
        LocalDateTime end = null;
        if ("fixed".equals(coupon.getValidType())) {
            //固定时间
            if (coupon.getDaysToTakeEffect() != null && coupon.getDaysToTakeEffect() > 0) {
                start = LocalDateTimeUtil.offset(start, coupon.getDaysToTakeEffect(), ChronoUnit.DAYS).with(LocalTime.MIN);
            }
            end = LocalDateTimeUtil.offset(start, coupon.getValidDays(), ChronoUnit.DAYS).with(LocalTime.MAX).truncatedTo(ChronoUnit.SECONDS);
        } else if ("custom".equals(coupon.getValidType())) {
            //自定义时间
            start = coupon.getValidStartTime();
            end = coupon.getValidEndTime();
        }
        List<MkShopCouponRecord> recordList = new ArrayList<>();
        for (int i = 0; i < number; i++) {
            MkShopCouponRecord record = new MkShopCouponRecord();
            record.setShopId(giftDTO.getShopId());
            record.setShopUserId(giftDTO.getShopUserId());
            record.setUserId(shopUser.getUserId());
            record.setCouponId(giftDTO.getCouponId());
            record.setCouponSyncId(coupon.getSyncId());
            record.setSourceId(giftDTO.getSourceId());
            record.setSourceFlowId(giftDTO.getSourceFlowId());
            record.setSource(giftDTO.getSource());
            record.setStatus(0);
            record.setType(coupon.getCouponType());
            record.setFullAmount(coupon.getFullAmount());
            record.setDiscountAmount(coupon.getDiscountAmount());
            record.setDiscountRate(coupon.getDiscountRate());
            record.setMaxDiscountAmount(coupon.getMaxDiscountAmount());
            record.setCreateTime(LocalDateTime.now());
            record.setIsDel(0);
            record.setCouponJson(couponJson);
            record.setName(coupon.getTitle());

            record.setUseStartTime(start);
            record.setUseEndTime(end);
//            save(record);
            recordList.add(record);
        }
        mapper.insertBatchSelective(recordList, 10);
        QueryWrapper queryWrapper = new QueryWrapper();
        ShopCoupon newCoupon = new ShopCoupon();
        newCoupon.setLeftNum(coupon.getLeftNum());
        newCoupon.setGiftNum(coupon.getGiftNum());
        if (coupon.getSyncId() != null) {
            queryWrapper.and(q -> {
                q.eq(ShopCoupon::getId, coupon.getSyncId()).or(q1 -> {
                    q1.eq(ShopCoupon::getSyncId, coupon.getSyncId());
                });
            });
            couponService.updateByQuery(newCoupon, queryWrapper);
        } else {
            newCoupon.setId(coupon.getId());
            couponService.update(newCoupon, true);
        }
    }


    /**
     * 发放券 批量发放  不计限领
     * 检查优惠券状态  检查店铺ID是否存在且与发放店铺一致 检查优惠券是否失效
     *
     * @param giftDTO 除 sourceFlowId shopUserId外 全必填 如果有 也填
     * @param number  发放数量
     */
    private void batchReceiveCoupon(MkShopCouponGiftDTO giftDTO, Integer number, List<ShopUser> userList) {
        if (number == null || number <= 0) {
            throw new CzgException("发放数量不能小于0");
        }
        AssertUtil.isNull(giftDTO.getShopId(), "店铺id不能为空");
        AssertUtil.isNull(giftDTO.getCouponId(), "优惠券id不能为空");
        AssertUtil.isNull(giftDTO.getSourceId(), "来源活动id不能为空");
        AssertUtil.isBlank(giftDTO.getSource(), "来源描述不能为空");
        ShopInfo shopInfo = shopInfoService.getById(giftDTO.getShopId());
        AssertUtil.isNull(shopInfo, "店铺不存在");
        ShopCoupon coupon = couponService.selectOneById(giftDTO.getCouponId());
        AssertUtil.isNull(coupon, "优惠券不存在");
        // 检查优惠券状态
        if (coupon.getIsDel() != 0) {
            // 状态异常，直接返回
            return;
        }
        // 检查店铺ID是否存在且与发放店铺一致
        if (coupon.getShopId() == null || !coupon.getShopId().equals(giftDTO.getShopId())) {
            return;
        }
        // 检查优惠券是否失效
        if (coupon.getStatus() != 1) {
            return;
        }

        coupon.setGiftNum(coupon.getGiftNum() + userList.size() * number);
        String couponJson = JSONObject.toJSONString(coupon);
        LocalDateTime start = LocalDateTime.now().with(LocalTime.MIN);
        LocalDateTime end = null;
        if ("fixed".equals(coupon.getValidType())) {
            //固定时间
            if (coupon.getDaysToTakeEffect() != null && coupon.getDaysToTakeEffect() > 0) {
                start = LocalDateTimeUtil.offset(start, coupon.getDaysToTakeEffect(), ChronoUnit.DAYS).with(LocalTime.MIN);
            }
            end = LocalDateTimeUtil.offset(start, coupon.getValidDays(), ChronoUnit.DAYS).with(LocalTime.MAX).truncatedTo(ChronoUnit.SECONDS);
        } else if ("custom".equals(coupon.getValidType())) {
            //自定义时间
            start = coupon.getValidStartTime();
            end = coupon.getValidEndTime();
        }
        List<MkShopCouponRecord> recordList = new ArrayList<>();
        for (int i = 0; i < number; i++) {
            for (ShopUser shopUser : userList) {
                MkShopCouponRecord record = new MkShopCouponRecord();
                record.setShopId(giftDTO.getShopId());
                record.setShopUserId(shopUser.getId());
                record.setUserId(shopUser.getUserId());
                record.setCouponId(giftDTO.getCouponId());
                record.setCouponSyncId(coupon.getSyncId());
                record.setSourceId(giftDTO.getSourceId());
                record.setSourceFlowId(giftDTO.getSourceFlowId());
                record.setSource(giftDTO.getSource());
                record.setStatus(0);
                record.setType(coupon.getCouponType());
                record.setFullAmount(coupon.getFullAmount());
                record.setDiscountAmount(coupon.getDiscountAmount());
                record.setDiscountRate(coupon.getDiscountRate());
                record.setMaxDiscountAmount(coupon.getMaxDiscountAmount());
                record.setCreateTime(LocalDateTime.now());
                record.setIsDel(0);
                record.setCouponJson(couponJson);
                record.setName(coupon.getTitle());

                record.setUseStartTime(start);
                record.setUseEndTime(end);
                recordList.add(record);
            }
        }
        mapper.insertBatchSelective(recordList, 50);
        QueryWrapper queryWrapper = new QueryWrapper();
        ShopCoupon newCoupon = new ShopCoupon();
        newCoupon.setGiftNum(coupon.getGiftNum());
        if (coupon.getSyncId() != null) {
            queryWrapper.and(q -> {
                q.eq(ShopCoupon::getId, coupon.getSyncId()).or(q1 -> {
                    q1.eq(ShopCoupon::getSyncId, coupon.getSyncId());
                });
            });
            couponService.updateByQuery(newCoupon, queryWrapper);
        } else {
            newCoupon.setId(coupon.getId());
            couponService.update(newCoupon, true);
        }
    }

    @Override
    public void deleteRecord(Long id) {
//        updateById(new MkShopCouponRecord().setId(id).setIsDel(1), true);
        updateById(new MkShopCouponRecord().setId(id).setStatus(2), true);
    }

    @Override
    @Transactional
    public Boolean grant(Long shopId, MkRewardCouponDTO rewardCouponDTO, String source) {
        Long mainIdByShopId = shopInfoService.getMainIdByShopId(shopId);
        ShopUser shopUser = shopUserService.getOne(new QueryWrapper().eq(ShopUser::getMainShopId, mainIdByShopId).eq(ShopUser::getUserId, rewardCouponDTO.getUserId()));
        MkShopCouponGiftDTO giftDTO = new MkShopCouponGiftDTO().setCouponId(rewardCouponDTO.getCouponId())
                .setShopId(shopId)
                .setSourceId(rewardCouponDTO.getUserId())
                .setShopUserId(shopUser == null ? null : shopUser.getId())
                .setSource(source);
        receiveCoupon(giftDTO, rewardCouponDTO.getNum(), false);
        return true;
    }

    /**
     * 组装信息
     */
    @Override
    public MkShopCouponRecord assembleRecord(Long chatCouponId, ShopCoupon coupon) {
        MkShopCouponRecord record = new MkShopCouponRecord();
        record.setShopId(coupon.getShopId());
        record.setCouponName(coupon.getTitle());
        record.setName(coupon.getTitle());
        record.setCouponId(coupon.getId());
        record.setCouponSyncId(coupon.getSyncId());
        record.setSourceId(chatCouponId);
        record.setSource("群聊发放");
        record.setStatus(0);
        record.setType(coupon.getCouponType());
        record.setFullAmount(coupon.getFullAmount());
        record.setDiscountAmount(coupon.getDiscountAmount());
        record.setDiscountRate(coupon.getDiscountRate());
        record.setMaxDiscountAmount(coupon.getMaxDiscountAmount());
        record.setCreateTime(LocalDateTime.now());
        record.setIsDel(0);
        record.setValidType(coupon.getValidType());
        if ("fixed".equals(coupon.getValidType())) {
            record.setDaysToTakeEffect(coupon.getDaysToTakeEffect());
            record.setValidDays(coupon.getValidDays());
        } else if ("custom".equals(coupon.getValidType())) {
            record.setUseStartTime(coupon.getValidStartTime());
            record.setUseEndTime(coupon.getValidEndTime());
        }
        return record;
    }

    @Override
    @Transactional
    public void grantChatCoupon(MkShopCouponRecord record, Integer number) {
        ShopCoupon coupon = couponService.selectOneById(record.getCouponId());
        AssertUtil.isNull(coupon, "优惠券不存在");
        List<MkShopCouponRecord> recordList = new ArrayList<>();
        // 检查优惠券状态
        if (coupon.getIsDel() != 0) {
            // 状态异常，直接返回
            return;
        }
        // 检查优惠券是否失效
        if (coupon.getStatus() != 1) {
            return;
        }
        //组装 发放优惠券
        if ("fixed".equals(record.getValidType())) {
            LocalDateTime start = LocalDateTime.now().with(LocalTime.MIN);
            //固定时间
            if (record.getDaysToTakeEffect() != null && record.getDaysToTakeEffect() > 0) {
                start = LocalDateTimeUtil.offset(start, record.getDaysToTakeEffect(), ChronoUnit.DAYS).with(LocalTime.MIN);
            }
            LocalDateTime end = LocalDateTimeUtil.offset(start, record.getValidDays(), ChronoUnit.DAYS).with(LocalTime.MAX).truncatedTo(ChronoUnit.SECONDS);
            record.setUseStartTime(start);
            record.setUseEndTime(end);
        }
        for (int i = 0; i < number; i++) {
            recordList.add(record);
        }
        mapper.insertBatchSelective(recordList, 10);

        QueryWrapper queryWrapper = new QueryWrapper();
        ShopCoupon newCoupon = new ShopCoupon();
        newCoupon.setGiftNum(coupon.getGiftNum() + number);
        if (coupon.getSyncId() != null) {
            queryWrapper.and(q -> {
                q.eq(ShopCoupon::getId, coupon.getSyncId()).or(q1 -> {
                    q1.eq(ShopCoupon::getSyncId, coupon.getSyncId());
                });
            });
            couponService.updateByQuery(newCoupon, queryWrapper);
        } else {
            newCoupon.setId(coupon.getId());
            couponService.update(newCoupon, true);
        }
    }
}
