package cn.ysk.cashier.mybatis.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.ysk.cashier.cons.TableConstant;
import cn.ysk.cashier.dto.CouponDto;
import cn.ysk.cashier.dto.QueryReceiveDto;
import cn.ysk.cashier.dto.TbShopCouponQueryCriteria;
import cn.ysk.cashier.exception.BadRequestException;
import cn.ysk.cashier.mybatis.entity.*;
import cn.ysk.cashier.mybatis.mapper.*;
import cn.ysk.cashier.mybatis.service.*;
import cn.ysk.cashier.mybatis.vo.TbShopCouponVo;
import cn.ysk.cashier.pojo.order.TbCashierCart;
import cn.ysk.cashier.pojo.order.TbOrderDetail;
import cn.ysk.cashier.pojo.order.TbOrderInfo;
import cn.ysk.cashier.pojo.product.TbProduct;
import cn.ysk.cashier.pojo.shop.TbShopUser;
import cn.ysk.cashier.repository.order.TbOrderDetailRepository;
import cn.ysk.cashier.repository.order.TbOrderInfoRepository;
import cn.ysk.cashier.repository.product.TbProductRepository;
import cn.ysk.cashier.repository.shop.TbShopUserRepository;
import cn.ysk.cashier.service.shop.TbShopUserService;
import cn.ysk.cashier.utils.PageUtil;
import cn.ysk.cashier.vo.QueryReceiveVo;
import cn.ysk.cashier.vo.TbUserCouponVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.gson.JsonObject;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 优惠券(TbShopCoupon)表服务实现类
 *
 * @author ww
 * @since 2024-10-22 15:43:25
 */
@Service("tbShopCouponService")
public class TbShopCouponServiceImpl extends ServiceImpl<TbShopCouponMapper, TbShopCoupon> implements TbShopCouponService {

    @Autowired
    private TbShopCouponMapper tbShopCouponmapper;
    @Autowired
    private TbActivateMapper activateMapper;
    @Autowired
    private TbCouponProductService couProductService;
    @Autowired
    private TbProductRepository tbProductRepository;
    @Autowired
    private TbShopUserRepository shopUserRepository;
    @Autowired
    private TbOrderInfoRepository orderInfoRepository;
    @Autowired
    private TbOrderDetailRepository orderDetailRepository;
    @Autowired
    private TbActivateInRecordMapper inRecordMapper;
    @Autowired
    private TbActivateOutRecordMapper outRecordMapper;
    @Autowired
    private TbShopShareRecordService shareRecordService;
    private final MpShopUserService shopUserService;
    private final MpOrderInfoService mpOrderInfoService;
    private final MpCashierCartService mpCashierCartService;

    public TbShopCouponServiceImpl(MpShopUserService shopUserService, MpOrderInfoService mpOrderInfoService, MpCashierCartService mpCashierCartService) {
        this.shopUserService = shopUserService;
        this.mpOrderInfoService = mpOrderInfoService;
        this.mpCashierCartService = mpCashierCartService;
    }


    @Override
    public Map<String, Object> queryAll(TbShopCouponQueryCriteria criteria) {
        Page<TbShopCoupon> page = new Page<>(criteria.getPage(), criteria.getSize());
        QueryWrapper<TbShopCoupon> wrapper = new QueryWrapper<>();
        wrapper.eq("shop_id", criteria.getShopId());
        if (criteria.getType() != null) {
            wrapper.eq("type", criteria.getType());
        }
        wrapper.orderByDesc("create_time");
        Page<TbShopCoupon> ipage = tbShopCouponmapper.selectPage(page, wrapper);
        return PageUtil.toPage(ipage.getRecords(), ipage.getTotal());
    }

    @Override
    public Map<String, Object> queryReceive(QueryReceiveDto param) {
        Page<QueryReceiveVo> page = new Page<>(param.getPage(), param.getSize());
        Page<QueryReceiveVo> ipage = tbShopCouponmapper.queryReceive(param, page);
        return PageUtil.toPage(ipage.getRecords(), ipage.getTotal());
    }

    @Override
    public TbShopCouponVo findById(Integer id) {
        TbShopCouponVo tbShopCouponVo = new TbShopCouponVo();
        TbShopCoupon tbShopCoupon = tbShopCouponmapper.selectById(id);
        BeanUtil.copyProperties(tbShopCoupon, tbShopCouponVo, CopyOptions.create().setIgnoreNullValue(true));
        if (tbShopCoupon.getType() == 2) {
            List<TbCouponProduct> activatePros = findActivatePros(id);
            tbShopCouponVo.setProducts(activatePros);
        }
        return tbShopCouponVo;
    }

    @Override
    public boolean update(TbShopCouponVo param) {
        if (param.getId() == null) {
            param.setLeftNumber(param.getNumber());
            tbShopCouponmapper.insert(param);
        } else {
            if (param.getNumber() != null) {
                TbShopCoupon tbShopCoupon = tbShopCouponmapper.selectById(param.getId());
                if (param.getNumber() < tbShopCoupon.getNumber()) {
                    throw new BadRequestException("修改失败 发放数量不可减少");
                } else {
                    param.setLeftNumber(param.getLeftNumber() + param.getNumber() - tbShopCoupon.getNumber());
                }
            }
            tbShopCouponmapper.updateById(param);
        }
        if (CollectionUtil.isNotEmpty(param.getProducts())) {
            List<Integer> collect = new ArrayList<>();
            for (TbCouponProduct product : param.getProducts()) {
                product.setCouponId(param.getId());
                if (product.getId() != null) collect.add(product.getId());
            }
            QueryWrapper<TbCouponProduct> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("coupon_id", param.getId());
            List<TbCouponProduct> actProducts = couProductService.list(queryWrapper);
            for (TbCouponProduct actProduct : actProducts) {
                if (!collect.contains(actProduct.getId())) {
                    couProductService.removeById(actProduct.getId());
                }
            }
            couProductService.saveOrUpdateBatch(param.getProducts());
        } else {
            LambdaQueryWrapper<TbCouponProduct> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(TbCouponProduct::getCouponId, param.getId());
            couProductService.remove(queryWrapper);
        }
        return true;
    }

    @Override
    public boolean deleteReceive(Integer[] ids) {
        inRecordMapper.deleteBatchIds(Arrays.asList(ids));
        return true;
    }

    @Override
    public boolean delete(Integer[] ids) {
        for (Integer id : ids) {
            List<TbActivate> tbActivates = activateMapper.queActByCouponId(id);
            if (CollectionUtil.isNotEmpty(tbActivates)) {
                throw new BadRequestException("该优惠券已关联活动，请解绑后删除");
            }
            Integer i = inRecordMapper.countNoUseCoupon(id);
            if (i != null && i > 0) {
                throw new BadRequestException("该优惠券有发放后未使用，无法删除");
            }
        }
        tbShopCouponmapper.deleteBatchIds(Arrays.asList(ids));
        for (Integer id : ids) {
            couProductService.remove(new LambdaQueryWrapper<TbCouponProduct>().eq(TbCouponProduct::getCouponId, id));
        }
        return true;
    }

    @Override
    public List<TbUserCouponVo> getActivateCoupon(TbShopUser tbShopUser, BigDecimal orderAmount, Integer shopId, Set<String> productIds) {
        List<TbUserCouponVo> tbUserCouponVos = inRecordMapper.queryByVipIdAndShopId(tbShopUser.getId(), shopId);
        if (tbUserCouponVos.isEmpty()) {
            return tbUserCouponVos;
        }
        String week = DateUtil.dayOfWeekEnum(new Date()).toChinese("周");
        LocalTime now = LocalTime.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm:ss");
        //券id 券使用描述
        Map<Integer, JsonObject> coupons = new HashMap<>();
        for (TbUserCouponVo tbUserCouponVo : tbUserCouponVos) {
            if (!coupons.containsKey(tbUserCouponVo.getCouponId())) {
                setCouponInfo(coupons, tbUserCouponVo, orderAmount, week, now, formatter);
            }
            JsonObject couponJson = coupons.get(tbUserCouponVo.getCouponId());
            tbUserCouponVo.setUseRestrictions(couponJson.get("useRestrictions").toString());
            if (tbUserCouponVo.getType().equals(1)) {
                tbUserCouponVo.setUse(couponJson.get("isUse").getAsBoolean());
            } else if (tbUserCouponVo.getType().equals(2) && couponJson.get("isUse").getAsBoolean()) {
                tbUserCouponVo.setUse(couponJson.get("isUse").getAsBoolean());
                if (!productIds.contains(tbUserCouponVo.getProId().toString())) {
                    tbUserCouponVo.setUse(false);
                }
            }
        }
        tbUserCouponVos.sort(Comparator.comparing(TbUserCouponVo::isUse).reversed().thenComparing(TbUserCouponVo::getExpireTime));
        return tbUserCouponVos;
    }

    private void setCouponInfo(Map<Integer, JsonObject> coupons, TbUserCouponVo tbUserCouponVo, BigDecimal amount, String week, LocalTime now, DateTimeFormatter formatter) {
        JsonObject json = new JsonObject();
        boolean isUse = true;
        TbShopCoupon tbShopCoupon = getById(tbUserCouponVo.getCouponId());
        StringBuilder useRestrictions = new StringBuilder("每天 ");
        if (tbShopCoupon.getType().equals(1)) {
            if (amount.compareTo(tbShopCoupon.getFullAmount()) < 0) {
                isUse = false;
            }
        }
        if (StringUtils.isNotBlank(tbShopCoupon.getUserDays())) {
            String[] split = tbShopCoupon.getUserDays().split(",");
            if (split.length != 7) {
                useRestrictions = new StringBuilder(tbShopCoupon.getUserDays() + " ");
            }
            if (!tbShopCoupon.getUserDays().contains(week)) {
                isUse = false;
            }
        }
        if (tbShopCoupon.getUseTimeType().equals("custom")) {
            if (now.isBefore(tbShopCoupon.getUseStartTime()) || now.isAfter(tbShopCoupon.getUseEndTime())) {
                isUse = false;
            }
            useRestrictions.append(
                    tbShopCoupon.getUseStartTime().format(formatter)
                            + "-"
                            + tbShopCoupon.getUseEndTime().format(formatter));
        } else {
            useRestrictions.append("全时段");
        }
        useRestrictions.append(" 可用");
        json.addProperty("isUse", isUse);
        json.addProperty("useRestrictions", useRestrictions.toString());

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


    @Override
    public ResponseEntity<Object> find(CouponDto param) {
        TbShopUser tbShopUser = shopUserRepository.selectByUserIdAndShopId(param.getUserId().toString(), param.getShopId().toString());
        if (param.getOrderId() != null) {
            List<TbUserCouponVo> tbUserCouponVos = inRecordMapper.queryByVipIdAndShopId(tbShopUser.getId(), param.getShopId());
            if (CollectionUtil.isNotEmpty(tbUserCouponVos)) {
                String week = DateUtil.dayOfWeekEnum(new Date()).toChinese("周");
                LocalTime now = LocalTime.now();
                DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm:ss");

                //券id 券使用描述
                Map<Integer, JsonObject> coupons = new HashMap<>();
                for (TbUserCouponVo tbUserCouponVo : tbUserCouponVos) {
                    if (!coupons.containsKey(tbUserCouponVo.getCouponId())) {
                        setCouponInfo(coupons, tbUserCouponVo, null, week, now, formatter);
                    }
                    JsonObject couponJson = coupons.get(tbUserCouponVo.getCouponId());
                    tbUserCouponVo.setUseRestrictions(couponJson.get("useRestrictions").toString());
                    tbUserCouponVo.setUse(couponJson.get("isUse").getAsBoolean());
                }
                tbUserCouponVos.sort(Comparator.comparing(TbUserCouponVo::isUse).reversed().thenComparing(TbUserCouponVo::getExpireTime));
                return new ResponseEntity<>(tbUserCouponVos, HttpStatus.OK);
            }
        }
        return new ResponseEntity<>(HttpStatus.OK);
    }

    /**
     * 使用券
     *
     * @param shopId
     * @param orderId
     * @param vipUserId
     * @param param     giveId 和 useNum 必传
     * @return
     */
    @Override
    public boolean use(Integer shopId, Integer orderId, Integer vipUserId, List<TbActivateOutRecord> param) {
        for (TbActivateOutRecord outRecord : param) {
            TbActivateInRecord inRecord = inRecordMapper.selectById(outRecord.getGiveId());
            if (inRecord.getSource() != null && inRecord.getSource().equals("invited")) {
                TbShopShareRecord shareRecord = shareRecordService.getById(inRecord.getSourceActId());
                if (shareRecord != null && shareRecord.getMethod().equals("use")) {
                    shareRecord.setStatus(3);
                    shareRecordService.give(shareRecord, shareRecord.getInvitedId());
                    shareRecordService.updateById(shareRecord);
                }
            }

            inRecord.setOverNum(inRecord.getOverNum() - outRecord.getUseNum());
            inRecordMapper.updateOverNum(inRecord.getId(), inRecord.getOverNum());

            outRecord.setType(inRecord.getType());
            outRecord.setShopId(shopId);
            outRecord.setOrderId(orderId.toString());
            outRecord.setVipUserId(vipUserId);
            outRecord.setStatus("closed");
            outRecord.setCreateTime(new Date());
            outRecordMapper.insert(outRecord);
        }
        return true;
    }

    /**
     * 退还券
     *
     * @param param giveId和 refNum 必传
     * @return
     */
    @Override
    public boolean refund(List<TbActivateOutRecord> param) {
        for (TbActivateOutRecord outRecord : param) {
            outRecord.setUpdateTime(new Date());
            outRecordMapper.updateRefNum(outRecord.getId(), outRecord.getRefNum());
            TbActivateInRecord inRecord = inRecordMapper.selectById(outRecord.getGiveId());
            inRecord.setOverNum(inRecord.getOverNum() + outRecord.getRefNum());
            inRecordMapper.updateOverNum(inRecord.getId(), inRecord.getOverNum());
        }
        return true;
    }


    @Override
    public List<TbCouponProduct> findActivatePros(Integer couponId) {
        QueryWrapper<TbCouponProduct> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("coupon_id", couponId);
        List<TbCouponProduct> actProducts = couProductService.list(queryWrapper);
        if (!CollectionUtils.isEmpty(actProducts)) {
            for (TbCouponProduct actProduct : actProducts) {
                TbProduct product = tbProductRepository.findById(actProduct.getProductId()).orElse(null);
                if (product != null) {
                    actProduct.setName(product.getName());
                    actProduct.setCoverImg(product.getCoverImg());
                }
            }
            return actProducts;
        }
        return new ArrayList<>();
    }

    @Override
    public List<TbShopCoupon> selectByIds(List<Integer> couponIds) {
        return listByIds(couponIds);
    }

    @Override
    public Object getActivateByOrderIds(Integer shopId, Integer orderId, Integer memberId) {
        TbOrderInfo orderInfo = mpOrderInfoService.selectOrderByIdAndState(orderId, TableConstant.OrderInfo.Status.UNPAID);
        if (orderInfo == null) {
            throw new BadRequestException("订单信息不存在");
        }

        if (memberId == null && orderInfo.getMemberId() == null) {
            throw new BadRequestException("请先选择对应的会员信息");
        }

        if (memberId == null) {
            memberId = Integer.valueOf(orderInfo.getMemberId());
        }

        TbShopUser shopUser = shopUserService.getById(memberId);
        if (shopUser == null) {
            throw new BadRequestException("用户信息不存在");
        }

        List<TbCashierCart> cashierCarts = mpCashierCartService.selectByOrderIdAndState(orderId, TableConstant.OrderInfo.Status.CREATE, TableConstant.OrderInfo.Status.CLOSED, TableConstant.OrderInfo.Status.FINAL);
        List<TbUserCouponVo> activateCouponList = getActivateCoupon(shopUser, orderInfo.getOrderAmount(), shopId, cashierCarts.stream().map(TbCashierCart::getProductId).collect(Collectors.toSet()));
        // 将优惠券分类为满减和商品
        ArrayList<TbUserCouponVo> fullReductionCoupon = new ArrayList<>();
        ArrayList<TbUserCouponVo> productCoupon = new ArrayList<>();
        activateCouponList.forEach(item -> {
            if (TableConstant.ActivateOutRecord.Type.FULL_REDUCTION.equalsVals(item.getType())) {
                fullReductionCoupon.add(item);
            } else {
                productCoupon.add(item);
            }
        });
        return new HashMap<String, Object>() {{
            put("fullReductionCoupon", fullReductionCoupon);
            put("productCoupon", productCoupon);
        }};
    }


}

