package com.czg.service.account.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.exceptions.ValidateException;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.czg.account.dto.QueryReceiveDto;
import com.czg.account.dto.ShopCouponDTO;
import com.czg.account.entity.ShopActivateCouponRecord;
import com.czg.account.entity.ShopCoupon;
import com.czg.account.entity.ShopUser;
import com.czg.account.service.ShopActivateCouponRecordService;
import com.czg.account.service.ShopCouponService;
import com.czg.account.service.ShopInfoService;
import com.czg.account.service.ShopUserService;
import com.czg.account.vo.CouponReceiveVo;
import com.czg.account.vo.UserCouponVo;
import com.czg.product.entity.Product;
import com.czg.product.service.ProductService;
import com.czg.service.account.mapper.ShopCouponMapper;
import com.czg.utils.AssertUtil;
import com.czg.utils.PageUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.mybatisflex.core.paginate.Page;
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.math.BigDecimal;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 优惠券 服务层实现。
 *
 * @author ww
 * @since 2025-02-17
 */
@Slf4j
@DubboService
public class ShopCouponServiceImpl extends ServiceImpl<ShopCouponMapper, ShopCoupon> implements ShopCouponService {

    @Resource
    private ShopActivateCouponRecordService couponRecordService;
    @Resource
    private ShopUserService shopUserService;
    @Resource
    private ShopInfoService shopInfoService;
    @DubboReference
    private ProductService productService;

    @Override
    public List<ShopCouponDTO> getList(Long shopId, Integer type, Integer status) {
        List<ShopCouponDTO> coupons = queryChain().select()
                .eq(ShopCoupon::getShopId, shopId)
                .eq(ShopCoupon::getType, type)
                .eq(ShopCoupon::getStatus, status)
                .orderBy(ShopCoupon::getCreateTime).desc()
                .listAs(ShopCouponDTO.class);
        System.out.println(coupons);
        coupons.forEach(coupon -> {
            if (coupon.getProId() != null) {
                Product product = productService.getById(coupon.getProId());
                coupon.setProName(product.getName());
            }
        });
        return coupons;
    }

    @Override
    public Boolean add(ShopCouponDTO couponDTO) {
        ShopCoupon shopCoupon = new ShopCoupon();
        BeanUtil.copyProperties(couponDTO, shopCoupon);
        shopCoupon.setLeftNumber(shopCoupon.getNumber());
        return save(shopCoupon);
    }

    @Override
    public Boolean edit(ShopCouponDTO couponDTO) {
        ShopCoupon shopCoupon = new ShopCoupon();
        BeanUtil.copyProperties(couponDTO, shopCoupon);
        if (couponDTO.getNumber() != null) {
            ShopCoupon tbShopCoupon = getById(couponDTO.getId());
            if (shopCoupon.getNumber() < tbShopCoupon.getNumber()) {
                throw new ValidateException("修改失败 发放数量不可减少");
            } else {
                shopCoupon.setLeftNumber(shopCoupon.getLeftNumber() + shopCoupon.getNumber() - tbShopCoupon.getNumber());
            }
        }
        return updateById(shopCoupon);
    }

    @Override
    public Page<CouponReceiveVo> queryReceive(QueryReceiveDto param) {
        Page<Object> page = PageUtil.buildPage();
        PageHelper.startPage(Math.toIntExact(page.getPageNumber()), Math.toIntExact(page.getPageSize()));
        return PageUtil.convert(new PageInfo<>(couponRecordService.queryReceive(param)));
    }


    @Override
    public Page<ShopActivateCouponRecord> find(Long userId, Long shopId, Integer status) {
        Page<Object> page = PageUtil.buildPage();
        List<Long> shopUserIds = shopUserService.queryChain()
                .eq(ShopUser::getUserId, userId)
                .eq(ShopUser::getShopId, shopId)
                .select(ShopUser::getId).listAs(Long.class);
        if (CollectionUtil.isNotEmpty(shopUserIds)) {
            PageHelper.startPage(Math.toIntExact(page.getPageNumber()), Math.toIntExact(page.getPageSize()));
            return PageUtil.convert(new PageInfo<>(couponRecordService.findByUser(shopUserIds, status)));
        }
        return new Page<>();
    }

    @Override
    public List<UserCouponVo> findCoupon(Long shopId, Long shopUserId, Integer type) {
        List<UserCouponVo> tbUserCouponVos = couponRecordService.queryByVipIdAndShopId(shopId, shopUserId, type);
        if (CollectionUtil.isNotEmpty(tbUserCouponVos)) {
            String week = DateUtil.dayOfWeekEnum(new Date()).toChinese("周");
            LocalTime now = LocalTime.now();
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm:ss");

            //券id 券使用描述
            Map<Long, JSONObject> coupons = new HashMap<>();
            for (UserCouponVo tbUserCouponVo : tbUserCouponVos) {
                if (!coupons.containsKey(tbUserCouponVo.getCouponId())) {
                    setCouponInfo(coupons, tbUserCouponVo, null, week, now, formatter);
                }
                JSONObject couponJson = coupons.get(tbUserCouponVo.getCouponId());
                tbUserCouponVo.setUseRestrictions(couponJson.getString("useRestrictions"));
                tbUserCouponVo.setUse(couponJson.getBoolean("isUse"));

            }
            tbUserCouponVos.sort(Comparator.comparing(UserCouponVo::isUse).reversed());
            return tbUserCouponVos;
        }
        return null;
    }

    @Override
    public Boolean use(List<Long> ids, Long shopUserId, Long orderId) {
        List<ShopActivateCouponRecord> records = couponRecordService.listByIds(ids);
        if (records.isEmpty()) {
            log.error("优惠券使用失败，订单Id:{}", orderId);
            return false;
        }
        // 使用流来统计 couponId 出现的次数
        Map<Long, Long> couponIdCountMap = records.stream()
                .collect(Collectors.groupingBy(ShopActivateCouponRecord::getCouponId,
                        Collectors.counting()
                ));
        couponIdCountMap.forEach((couponId, count) -> {
            ShopCoupon tbShopCoupon = getById(couponId);
            tbShopCoupon.setUseNumber(tbShopCoupon.getUseNumber() + count.intValue());
            ShopCoupon coupon1 = new ShopCoupon();
            coupon1.setId(couponId);
            coupon1.setUseNumber(tbShopCoupon.getUseNumber());
            updateById(coupon1);
        });
        return couponRecordService.updateChain()
                .set(ShopActivateCouponRecord::getStatus, 1)
                .set(ShopActivateCouponRecord::getTargetId, orderId)
                .eq(ShopActivateCouponRecord::getShopUserId, shopUserId)
                .in(ShopActivateCouponRecord::getId, ids).update();
    }

    /**
     * 退还券
     */
    @Override
    public Boolean refund(Long orderId, Long shopUserId) {
        return couponRecordService.updateChain()
                .set(ShopActivateCouponRecord::getStatus, 0)
                .eq(ShopActivateCouponRecord::getShopUserId, shopUserId)
                .eq(ShopActivateCouponRecord::getTargetId, orderId)
                .update();
    }

    private void setCouponInfo(Map<Long, JSONObject> coupons, UserCouponVo tbUserCouponVo, BigDecimal amount, String week, LocalTime now, DateTimeFormatter formatter) {
        JSONObject json = new JSONObject();
        boolean isUse = true;
        ShopCoupon tbShopCoupon = getById(tbUserCouponVo.getCouponId());
        StringBuilder useRestrictions = new StringBuilder("每天 ");
        if (amount != null && tbShopCoupon.getType().equals(1)) {
            if (amount.compareTo(tbShopCoupon.getFullAmount()) < 0) {
                isUse = false;
            }
        }
        if (StrUtil.isNotBlank(tbShopCoupon.getUserDays())) {
            String[] split = tbShopCoupon.getUserDays().split(",");
            if (split.length != 7) {
                useRestrictions = new StringBuilder(STR."\{tbShopCoupon.getUserDays()} ");
            }
            if (!tbShopCoupon.getUserDays().contains(week)) {
                isUse = false;
            }
        }
        if ("custom".equals(tbShopCoupon.getUseTimeType())) {
            if (now.isBefore(tbShopCoupon.getUseStartTime()) || now.isAfter(tbShopCoupon.getUseEndTime())) {
                isUse = false;
            }
            useRestrictions.append(
                    STR."\{tbShopCoupon.getUseStartTime().format(formatter)}-\{tbShopCoupon.getUseEndTime().format(formatter)}");
        } else {
            useRestrictions.append("全时段");
        }
        useRestrictions.append(" 可用");
        json.put("isUse", isUse);
        json.put("useRestrictions", useRestrictions);

        coupons.put(tbUserCouponVo.getCouponId(), json);
    }

}
