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

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.czg.account.entity.ShopInfo;
import com.czg.account.entity.ShopUser;
import com.czg.account.service.ShopInfoService;
import com.czg.account.service.ShopUserService;
import com.czg.config.RabbitPublisher;
import com.czg.constant.TableValueConstant;
import com.czg.market.dto.CouponInfoDTO;
import com.czg.market.dto.MkBirthdayGiftDTO;
import com.czg.market.dto.MkRewardCouponDTO;
import com.czg.market.dto.ShopCouponDTO;
import com.czg.market.entity.*;
import com.czg.market.service.*;
import com.czg.market.vo.MkBirthdayGiftRecordSummaryVO;
import com.czg.market.vo.MkBirthdayGiftRecordVO;
import com.czg.market.vo.MkBirthdayGiftVO;
import com.czg.service.market.mapper.MkBirthdayGiftMapper;
import com.czg.utils.FunUtils;
import com.czg.utils.MyQueryWrapper;
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.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 生日有礼 服务层实现。
 *
 * @author zs
 * @since 2025-10-14
 */
@Slf4j
@Service
@CacheConfig(cacheNames = "birthdayGift")
public class MkBirthdayGiftServiceImpl extends ServiceImpl<MkBirthdayGiftMapper, MkBirthdayGift> implements MkBirthdayGiftService {
    @Resource
    private MkBirthdayGiftRecordService birthdayGiftRecordService;
    @Resource
    private MkBirthdayGiftRecordCouponService birthdayGiftRecordCouponService;
    @Resource
    private ShopCouponService shopCouponService;
    @Resource
    private MkShopCouponRecordService shopCouponRecordService;
    @Resource
    private SmsShopTemplateService smsShopTemplateService;
    @Resource
    private ShopInfoService shopInfoService;
    @Resource
    private RabbitPublisher rabbitPublisher;

    @DubboReference
    private ShopUserService shopUserService;

    @Override
    @Cacheable(key = "#shopId")
    public MkBirthdayGiftVO detail(Long shopId) {
        MkBirthdayGift gift = getOne(new QueryWrapper().eq(MkBirthdayGift::getMainShopId, shopId));
        if (gift == null) {
            gift = new MkBirthdayGift();
            gift.setMainShopId(shopId);
            save(gift);
            gift = getOne(new QueryWrapper().eq(MkBirthdayGift::getMainShopId, shopId));
        }
        MkBirthdayGiftVO vo = BeanUtil.copyProperties(gift, MkBirthdayGiftVO.class, "configList");
        if (StrUtil.isNotBlank(gift.getConfigList())) {
            vo.setConfigList(JSONArray.parseArray(gift.getConfigList()).toJavaList(MkBirthdayGiftConfig.class));
        }
        return vo;
    }

    @Override
    public MkBirthdayGiftRecordSummaryVO summary(Long shopId, String key, LocalDateTime dateTime) {
        QueryWrapper queryWrapper = new MyQueryWrapper()
                .leftJoin(MkBirthdayGiftRecord.class).on(MkBirthdayGiftRecord::getId, MkBirthdayGiftRecordCoupon::getRecordId)
                .select("sum( IF(type = 'give', num, 0)) as totalNum", "sum( IF(type = 'consume', num, 0)) as usedNum")
                .eq(MkBirthdayGiftRecord::getMainShopId, shopId)
                .leftJoin(ShopUser.class).on(ShopUser::getId, MkBirthdayGiftRecord::getShopUserId);
        if (StrUtil.isNotBlank(key)) {
            queryWrapper.and(and -> {
                and.or(or -> {
                    or.like(ShopUser::getNickName, key);
                }).or(or -> {
                    or.like(ShopUser::getPhone, key);
                });
            });
        }

        return birthdayGiftRecordCouponService.getOneAsOpt(queryWrapper, MkBirthdayGiftRecordSummaryVO.class).orElseGet(MkBirthdayGiftRecordSummaryVO::new);
    }

    @Override
    @CacheEvict(key = "#shopId")
    public Boolean edit(Long shopId, MkBirthdayGiftDTO giftDTO) {
        MkBirthdayGift birthdayGift = getOne(new QueryWrapper().eq(MkBirthdayGift::getMainShopId, shopId));
        BeanUtil.copyProperties(giftDTO, birthdayGift);
        if (giftDTO.getConfigList() != null && !giftDTO.getConfigList().isEmpty()) {
            birthdayGift.setConfigList(JSONArray.toJSONString(giftDTO.getConfigList()));
        }
        return updateById(birthdayGift);
    }

    @Override
    public Page<MkBirthdayGiftRecordVO> getRecord(Long shopId, String key, LocalDateTime dateTime) {
        QueryWrapper queryWrapper = new MyQueryWrapper()
                .selectAll(MkBirthdayGiftRecord.class)
                .select(ShopUser::getNickName, ShopUser::getPhone)
                .eq(MkBirthdayGiftRecord::getMainShopId, shopId)
                .leftJoin(ShopUser.class).on(ShopUser::getId, MkBirthdayGiftRecord::getShopUserId);
        if (StrUtil.isNotBlank(key)) {
            queryWrapper.and(and -> {
                and.or(or -> {
                    or.like(ShopUser::getNickName, key);
                }).or(or -> {
                    or.like(ShopUser::getPhone, key);
                });
            });
        }

        Page<MkBirthdayGiftRecordVO> recordVOPage = birthdayGiftRecordService.pageAs(PageUtil.buildPage(), queryWrapper, MkBirthdayGiftRecordVO.class);
        recordVOPage.getRecords().forEach(item -> {
            item.setCouponList(new ArrayList<>());
            List<MkBirthdayGiftRecordCoupon> list = birthdayGiftRecordCouponService.list(new QueryWrapper().eq(MkBirthdayGiftRecordCoupon::getRecordId, item.getId()));
            item.setCouponList(list);
        });
        return recordVOPage;
    }

    @Override
    public void deliver() {
        DateTime now = DateUtil.date();
        list(new QueryWrapper().eq(MkBirthdayGift::getIsEnable, 1)).forEach(birthdayGift -> {
            if (StrUtil.isNotBlank(birthdayGift.getConfigList())) {
                SmsShopTemplate shopTemplate;
                if (birthdayGift.getTemplateId() != null) {
                    shopTemplate = smsShopTemplateService.getById(birthdayGift.getTemplateId());
                } else {
                    shopTemplate = null;
                }
                ShopInfo shopInfo = shopInfoService.getById(birthdayGift.getMainShopId());
                FunUtils.safeRunVoid(() -> JSONArray.parseArray(birthdayGift.getConfigList()).toJavaList(MkBirthdayGiftConfig.class).forEach(config -> {
                    LocalDate current = DateUtil.date().toLocalDateTime().toLocalDate();
                    if ("day".equals(config.getDeliverDate())) {
                        if (config.getDeliverTime() != 1) {
                            current = current.plusDays(config.getDeliverTime());
                        }
                    } else {
                        // 获取当月第一天
                        current = DateUtil.beginOfMonth(now).toLocalDateTime().toLocalDate();
                    }
                    List<ShopUser> shopUserList = shopUserService.selectBirthdayUser(current, birthdayGift.getMainShopId(), config.getUserType());
                    log.info("符合用户, {}", shopUserList);
                    for (ShopUser shopUser : shopUserList) {
                        long count = birthdayGiftRecordService.count(new QueryWrapper().eq(MkBirthdayGiftRecord::getUserId, shopUser.getUserId())
                                        .eq(MkBirthdayGiftRecord::getYear, DateUtil.year(now)));
                        if (count > 1) {
                            log.info("用户{}已领取过生日礼包", shopUser.getUserId());
                            continue;
                        }
                        // 发放记录
                        MkBirthdayGiftRecord giftRecord = new MkBirthdayGiftRecord().setUserId(shopUser.getUserId()).setShopUserId(shopUser.getId())
                                .setPushStatus(birthdayGift.getSendSms() == 1 ?
                                        TableValueConstant.BirthdayGiftRecord.PushStatus.WAIT_PUSH.getCode() : TableValueConstant.BirthdayGiftRecord.PushStatus.NO_PUSH.getCode())
                                .setMainShopId(birthdayGift.getMainShopId()).setBirthday(DateUtil.parseDate(shopUser.getBirthDay()).toLocalDateTime().toLocalDate())
                                .setPhone(shopUser.getPhone()).setTemplateId(shopTemplate == null ? null : shopTemplate.getId())
                                .setYear(DateUtil.year(now)).setUserType(config.getUserType())
                                .setSourceId(birthdayGift.getId()).setTemplateCode(shopTemplate == null ? null : shopTemplate.getTemplateCode()).setTemplateContent(JSONObject.toJSONString(Map.of(
                                        "用户昵称", shopUser.getNickName(),
                                        "店铺名称", shopInfo.getShopName(),
                                        "数量", config.getCouponInfoList() != null ? config.getCouponInfoList().stream().map(CouponInfoDTO::getNum).reduce(0, Integer::sum) : 0
                                )));
                        birthdayGiftRecordService.save(giftRecord);
                        rabbitPublisher.sendBirthdayGiftSmsMsg(giftRecord.getId().toString());

                        // 优惠券信息
                        if (config.getCouponInfoList() != null && !config.getCouponInfoList().isEmpty()) {
                            Map<Long, ShopCoupon> couponMap = shopCouponService.list(new QueryWrapper().in(ShopCoupon::getId, config.getCouponInfoList()
                                    .stream().map(CouponInfoDTO::getId).toList())).stream().collect(Collectors.toMap(ShopCoupon::getId, item -> item));
                            config.getCouponInfoList().forEach(couponInfo -> {
                                ShopCoupon shopCoupon = couponMap.get(couponInfo.getId());
                                if (shopCoupon == null) {
                                    log.warn("优惠券不存在, id: {}", couponInfo.getId());
                                    return;
                                }
                                FunUtils.safeRunVoid(() -> {
                                    shopCouponRecordService.grant(birthdayGift.getMainShopId(), new MkRewardCouponDTO().setCouponId(couponInfo.getId())
                                            .setNum(couponInfo.getNum())
                                            .setUserId(shopUser.getUserId())
                                            .setShopId(birthdayGift.getMainShopId()), "生日赠券");
                                    MkBirthdayGiftRecordCoupon recordCoupon = new MkBirthdayGiftRecordCoupon().setCouponName(shopCoupon.getTitle()).setNum(couponInfo.getNum())
                                            .setType(TableValueConstant.BirthdayGiftRecordCoupon.Type.GIVE.getCode())
                                            .setRecordId(giftRecord.getId()).setUserId(shopUser.getUserId()).setShopUserId(shopUser.getId());
                                    birthdayGiftRecordCouponService.save(recordCoupon);
                                }, "优惠券发放失败");
                            });
                        }
                    }
                }));

            }

        });
    }

    @Override
    public ArrayList<Map<String, Object>> getInfo(long userId, Integer shopId) {
        MkBirthdayGift birthdayGift = getOne(new QueryWrapper().eq(MkBirthdayGift::getMainShopId, shopId).eq(MkBirthdayGift::getIsEnable, 1));
        if (birthdayGift == null) {
            return null;
        }
        ShopUser shopUser = shopUserService.getOne(new QueryWrapper()
                .eq(ShopUser::getUserId, userId).isNotNull(ShopUser::getBirthDay)
                .eq(ShopUser::getMainShopId, shopId).eq(ShopUser::getBirthDayRemind, 0));
        if (shopUser == null) {
            return null;
        }
        if (StrUtil.isBlank(birthdayGift.getConfigList())) {
            return null;
        }
        try {
            //获取当天日期
            LocalDate current = DateUtil.date().toLocalDateTime().toLocalDate();
            // 解析用户生日（仅取月日）
            LocalDate userBirthday = DateUtil.parseDate(shopUser.getBirthDay()).toLocalDateTime().toLocalDate();
            // 构造当前年份的生日日期（用于区间判断）
            LocalDate thisYearBirthday = LocalDate.of(current.getYear(), userBirthday.getMonth(), userBirthday.getDayOfMonth());
            for (MkBirthdayGiftConfig config : JSONArray.parseArray(birthdayGift.getConfigList()).toJavaList(MkBirthdayGiftConfig.class)) {
                if ("day".equals(config.getDeliverDate())) {
                    // 获取偏移天数，默认为0（偏移天数应为非负数，代表未来的天数）
                    int offsetDays = config.getDeliverTime() != null ? Math.max(config.getDeliverTime(), 0) : 0;
                    // 计算偏移后的结束日期（当前日期 + 偏移天数）
                    LocalDate endDate = current.plusDays(offsetDays);
                    // 开始日期固定为当前日期
                    LocalDate startDate = current;

                    if (StrUtil.isNotBlank(shopUser.getBirthDay())) {
                        try {
                            // 如果生日在范围内，返回优惠券列表
                            if ((thisYearBirthday.isEqual(startDate) || thisYearBirthday.isAfter(startDate))
                                    && (thisYearBirthday.isEqual(endDate) || thisYearBirthday.isBefore(endDate))) {
                                shopUserService.updateById(new ShopUser().setId(shopUser.getId()).setBirthDayRemind(1));
                                return buildCouponList(config);
                            }
                        } catch (Exception e) {
                            log.error("解析用户生日失败", e);
                        }
                    }
                } else {
                    // 解析用户生日
                    if (StrUtil.isNotBlank(shopUser.getBirthDay())) {
                        // 判断当前月份是否等于用户生日月份
                        if (current.getMonthValue() == thisYearBirthday.getMonthValue()
                                && (current.isEqual(thisYearBirthday) || current.isBefore(thisYearBirthday))) {
                            shopUserService.updateById(new ShopUser().setId(shopUser.getId()).setBirthDayRemind(1));
                            return buildCouponList(config);
                        }
                    }
                }
            }
        } catch (Exception e) {
            log.error("获取生日礼包配置失败, shopUser: {}", shopUser, e);
            return null;
        }
        return null;
    }

    private ArrayList<Map<String, Object>> buildCouponList(MkBirthdayGiftConfig config) {
        ArrayList<Map<String, Object>> resultList = new ArrayList<>();
        if (config.getCouponInfoList() != null) {
            config.getCouponInfoList().forEach(item -> {
                ShopCouponDTO coupon = shopCouponService.getCouponById(item.getId());
                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();
                }
                coupon.setValidStartTime(start);
                coupon.setValidEndTime(end);
                resultList.add(Map.of(
                        "num", item.getNum(),
                        "couponInfo", coupon
                ));
            });
        }
        return resultList;
    }


}
