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

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.AShopUserService;
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.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.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 java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;

/**
 * 优惠券发放记录表 服务层实现。
 *
 * @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;
    @DubboReference
    private AShopUserService aShopUserService;
    @Resource
    private ShopCouponMapper couponService;


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

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

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


    @Override
    public Page<MkShopCouponRecordDTO> 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());
            }
        }
        return recordPage;
    }

    @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 = new ArrayList<>();
                if (param.getUserType() == 1) {
                    smsPushEventUser = new SmsPushEventUser();
                    smsPushEventUser.setShopId(param.getShopId());
                    smsPushEventUser.setIsAll(1);
                }
                userList = aShopUserService.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 = new ArrayList<>();
                if (param.getUserType() == 1) {
                    smsPushEventUser = new SmsPushEventUser();
                    smsPushEventUser.setShopId(param.getShopId());
                    smsPushEventUser.setIsAll(1);
                }
                userList = aShopUserService.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 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() != -10086 && 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();
        }
        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);
        }
        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);
            }
        }
        saveBatch(recordList);
        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
    public Boolean grant(Long shopId, MkRewardCouponDTO rewardCouponDTO) {
        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("后台发放");
        receiveCoupon(giftDTO, rewardCouponDTO.getNum(), false);
        return true;
    }
}
