package com.hfkj.service.order.impl;

import com.hfkj.common.exception.ErrorCode;
import com.hfkj.common.exception.ErrorHelp;
import com.hfkj.common.exception.SysCode;
import com.hfkj.common.utils.DateUtil;
import com.hfkj.common.utils.RandomUtils;
import com.hfkj.common.utils.RedisUtil;
import com.hfkj.dao.BsOrderMapper;
import com.hfkj.entity.*;
import com.hfkj.model.order.OrderChildModel;
import com.hfkj.model.order.OrderModel;
import com.hfkj.mqtopic.OrderTopic;
import com.hfkj.service.discount.BsDiscountUseMerService;
import com.hfkj.service.discount.BsDiscountUserService;
import com.hfkj.service.order.*;
import com.hfkj.sysenum.discount.DiscountTypeEnum;
import com.hfkj.sysenum.discount.DiscountUserStatusEnum;
import com.hfkj.sysenum.merchant.MerchantAccountRecordSourceTypeEnum;
import com.hfkj.sysenum.merchant.MerchantAccountRecordTypeEnum;
import com.hfkj.sysenum.order.OrderChildProductTypeEnum;
import com.hfkj.sysenum.order.OrderChildStatusEnum;
import com.hfkj.sysenum.order.OrderStatusEnum;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @className: BsOrderServiceImpl
 * @author: HuRui
 * @date: 2024/4/29
 **/
@Service("orderService")
public class BsOrderServiceImpl implements BsOrderService {
    // 缓存前缀KEY
    public final static String CACHE_KEY = "ORDER:";
    // 订单缓存时间 7天
    public final static Integer CACHE_TIME = 60*60*24*7;

    @Autowired
    private RedisUtil redisUtil;
    @Resource
    private RocketMQTemplate rocketMQTemplate;
    @Resource
    private BsOrderSettleService orderSettleService;
    @Resource
    private BsOrderMapper orderMapper;
    @Resource
    private BsOrderChildService orderChildService;
    @Resource
    private BsOrderDeductionService orderDeductionService;
    @Resource
    private BsDiscountUserService discountUserService;
    @Resource
    private OrderCreateService orderCreateService;
    @Resource
    private OrderPaySuccessService orderPaySuccessService;
    @Resource
    private OrderCancelService orderCancelService;
    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    public BsOrder editData(BsOrder order) {
        order.setUpdateTime(new Date());
        if (order.getId() == null) {
            order.setCreateTime(new Date());
            orderMapper.insert(order);
        } else {
            orderMapper.updateByPrimaryKey(order);
        }
        return order;
    }

    @Override
    public OrderModel cache(OrderModel order) {
        // 缓存
        redisUtil.set(CACHE_KEY + order.getOrderNo(), order, CACHE_TIME);
        return order;
    }

    @Override
    public void cacheDelete(String orderNo) {
        // 缓存
        redisUtil.del(CACHE_KEY + orderNo);
    }

    @Override
    @Transactional(
            propagation= Propagation.REQUIRES_NEW,
            isolation = Isolation.READ_COMMITTED,
            timeout = 20,
            rollbackFor = Exception.class)
    public OrderModel create(OrderModel order) throws Exception {
            // 生成交易单号，共18位，时间 + 6位随机数
            order.setOrderNo(DateUtil.date2String(new Date(), "yyMMddHHmmss") + RandomUtils.number(6, false));
            editData(order);

            /*****初始化优惠*****/
            BsOrderDeduction deduction = order.getDeduction()==null?new BsOrderDeduction():order.getDeduction();
            deduction.setOrderId(order.getId());
            deduction.setOrderNo(order.getOrderNo());
            deduction.setIntegralDiscountPrice(deduction.getIntegralDiscountPrice()==null?0L: deduction.getIntegralDiscountPrice());
            deduction.setCouponDiscountPrice(new BigDecimal("0"));
            deduction.setCouponDiscountActualPrice(new BigDecimal("0"));

            if (deduction.getUserCouponDiscountId() != null) {
                // 使用优惠券
                BsDiscountUser discountUser = discountUserService.userDiscount(deduction.getUserCouponDiscountId());
                deduction.setCouponDiscountId(discountUser.getDiscountId());
                deduction.setCouponDiscountNo(discountUser.getDiscountNo());
                deduction.setCouponDiscountType(discountUser.getDiscountType());
                deduction.setCouponDiscountPrice(discountUser.getDiscountPrice());

                if (DiscountTypeEnum.type1.getCode().equals(discountUser.getDiscountType())) {
                    // 如果订单总额 小于 满减价格
                    if (order.getTotalPrice().compareTo(discountUser.getDiscountCondition()) < 0) {
                        throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "未达到满减金额,无法使用此优惠券");
                    }
                    deduction.setCouponDiscountActualPrice(discountUser.getDiscountPrice());

                } else if (DiscountTypeEnum.type2.getCode().equals(discountUser.getDiscountType())) {
                    deduction.setCouponDiscountActualPrice(discountUser.getDiscountPrice());

                } else if (DiscountTypeEnum.type3.getCode().equals(discountUser.getDiscountType())) {
                    // 订单总额 - （订单总额 * 折扣） = 优惠金额
                    deduction.setCouponDiscountActualPrice(order.getTotalPrice().subtract(
                            order.getTotalPrice().multiply(discountUser.getDiscountPrice().divide(new BigDecimal("100"))).setScale(2, BigDecimal.ROUND_HALF_DOWN)
                    ));
                } else {
                    throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "未知的优惠券类型");
                }
            }

            deduction.setTotalDeductionPrice(deduction.getCouponDiscountActualPrice().add(new BigDecimal(deduction.getIntegralDiscountPrice().toString()).divide(new BigDecimal("100"))));
            orderDeductionService.editData(deduction);
            order.setDeduction(deduction);
            /*****初始化优惠*****/

            // 订单总金额
            BigDecimal totalPrice = new BigDecimal("0");
            // 商品总金额
            BigDecimal productTotalPrice = new BigDecimal("0");

            /************** 处理业务 ***************/
            for (OrderChildModel child : order.getOrderChildList()) {
                child.setOrderNo(order.getOrderNo());
                // 子订单号 交易id + 4位随机数
                child.setChildOrderNo(order.getId()+RandomUtils.number(4, false));
                // 提交订单前业务处理
                if (child.getProductType().equals(OrderChildProductTypeEnum.type1.getCode())) {
                    child = orderCreateService.oilHandle(order, deduction, child);
                }
                child.setProductTotalPrice(child.getProductActualPrice().multiply(new BigDecimal(child.getProductCount().toString())));
                child.setStatus(OrderChildStatusEnum.status1.getCode());

                productTotalPrice = productTotalPrice.add(child.getProductTotalPrice());
            }

            totalPrice = productTotalPrice;
            order.setTotalPrice(totalPrice);
            order.setProductTotalPrice(productTotalPrice);

            BigDecimal payRealPrice = totalPrice.subtract(order.getDeduction().getTotalDeductionPrice());
            if (order.getOrderChildList().get(0).getProductType().equals(OrderChildProductTypeEnum.type1.getCode())) {
                payRealPrice = totalPrice;
            }
            order.setPayRealPrice(payRealPrice.compareTo(new BigDecimal("0")) > 0 ? payRealPrice : new BigDecimal("0"));
            order.setOrderStatus(order.getPayRealPrice().compareTo(new BigDecimal("0")) == 0?OrderStatusEnum.status2.getCode():OrderStatusEnum.status1.getCode());
            // 订单入库前处理
            for (OrderChildModel childOrder : order.getOrderChildList()) {
                childOrder.setSurplusRefundCount(childOrder.getProductCount());

                // 计算 子订单 在交易订单金额中的占比
                BigDecimal ratio = childOrder.getProductTotalPrice().divide(order.getTotalPrice(), 2, BigDecimal.ROUND_DOWN);

                // 计算子订单退款积分
                if (order.getDeduction().getIntegralDiscountPrice() > 0) {
                    childOrder.setSurplusRefundIntegral(new BigDecimal(order.getDeduction().getIntegralDiscountPrice().toString()).multiply(ratio).setScale(2).longValue());
                } else {
                    childOrder.setSurplusRefundIntegral(0L);
                }

                if (order.getDeduction().getCouponDiscountActualPrice().compareTo(BigDecimal.ZERO) == 1) {
                    // 计算子订单退款金额。
                    if (order.getPayRealPrice().compareTo(BigDecimal.ZERO) == 1) {
                        // 计算实付金额中的占比
                        childOrder.setSurplusRefundPrice(order.getPayRealPrice().multiply(ratio).setScale(2, BigDecimal.ROUND_DOWN));
                    } else {
                        childOrder.setSurplusRefundPrice(new BigDecimal("0"));
                    }
                } else {
                    childOrder.setSurplusRefundPrice(
                            // 商品总金额 - 积分抵扣金额
                            childOrder.getProductTotalPrice().subtract(
                                    new BigDecimal(childOrder.getSurplusRefundIntegral().toString()).divide(new BigDecimal("100"))
                            ));
                }

                childOrder.setIntegralDiscountPrice(childOrder.getSurplusRefundIntegral());
                childOrder.setCouponDiscountPrice(
                        // 可退款金额大于0  可退款金额+可退款积分=优惠券优惠
                        childOrder.getSurplusRefundPrice().compareTo(BigDecimal.ZERO) == 1
                                ? childOrder.getProductTotalPrice().subtract(
                                childOrder.getSurplusRefundPrice().add(new BigDecimal(childOrder.getSurplusRefundIntegral().toString()).divide(new BigDecimal("100"))))
                                : childOrder.getSurplusRefundPrice());

                childOrder.setTotalDeductionPrice(
                        childOrder.getCouponDiscountPrice()
                                .add(new BigDecimal(childOrder.getIntegralDiscountPrice().toString()).divide(new BigDecimal("100")))
                );
                if (!childOrder.getProductType().equals(OrderChildProductTypeEnum.type1.getCode())) {
                    childOrder.setProductActualPrice(childOrder.getProductTotalPrice().subtract(childOrder.getTotalDeductionPrice()));
                }
                orderChildService.editData(childOrder);
            }
            // 订单入库
            editData(order);

            if (order.getOrderStatus().equals(OrderStatusEnum.status1.getCode())) {
                // 10分钟内未支付，自动取消订单
                Message<OrderModel> rocketMsg = MessageBuilder.withPayload(order).build();
                rocketMQTemplate.syncSend(OrderTopic.ORDER_TOPIC_CANCEL.getTopic(), rocketMsg,1000,14);

            } else if (order.getOrderStatus().equals(OrderStatusEnum.status2.getCode())) {
                // 支付校验
                //orderPayBeforeService.payOrderCheck(order);
                // 处理业务
                orderPaySuccessHandle(order);
            }
            // 更新缓存
            cache(order);
            return order;
    }

    @Override
    @Transactional(propagation= Propagation.REQUIRES_NEW, rollbackFor= {RuntimeException.class}, timeout = 10)
    public OrderModel cancel(String orderNo) {
        // 锁编号
        String lockKey = "ORDER_CANCEL_"+ orderNo;
        // 获取锁
        Boolean lock = redisTemplate.opsForValue().setIfAbsent(lockKey, "");
        if (Boolean.TRUE.equals(lock)) {
            try {
                // 获取锁成功
                // 查询订单
                OrderModel order = getDetail(orderNo);
                if (order == null) {
                    throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "未知的订单");
                }
                if (!order.getOrderStatus().equals(OrderStatusEnum.status1.getCode())) {
                    throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "无法取消，订单不处于待支付状态");
                }
                order.setOrderStatus(OrderStatusEnum.status5.getCode());
                order.setCancelTime(new Date());
                editData(order);

                for (BsOrderChild orderChild : order.getOrderChildList()) {
                    orderChild.setStatus(OrderChildStatusEnum.status5.getCode());
                    orderChildService.editData(orderChild);
                }
                if (order.getDeduction().getUserCouponDiscountId() != null) {
                    // 优惠券退回用户账户
                    discountUserService.revokeUserDiscount(order.getDeduction().getUserCouponDiscountId());
                }

        /*// 退款用户积分
        if (order.getDeduction().getIntegralDiscountPrice() > 0) {
            Map<String,Object> opUser = new HashMap<>();
            if (system) {
                opUser.put("opUserType", UserIntegralRecordOpUserTypeEnum.type1.getCode());
                opUser.put("opUserId", 0);
                opUser.put("opUserName", UserIntegralRecordOpUserTypeEnum.type1.getName());
            } else {
                opUser.put("opUserType", UserIntegralRecordOpUserTypeEnum.type3.getCode());
                opUser.put("opUserId", order.getUserId());
                opUser.put("opUserName", order.getUserName());
                opUser.put("opUserPhone", order.getUserPhone());
            }
            Map<String,Object> source = new HashMap<>();
            source.put("sourceType", UserIntegralRecordSourceTypeEnum.type1.getCode());
            source.put("sourceId", order.getId());
            source.put("sourceOrderNo", order.getOrderNo());
            source.put("sourceContent", "交易取消！退回积分");

            // 扣除用户积分
            userIntegralService.entry(
                    order.getUserId(),
                    order.getDeduction().getIntegralDiscountPrice(),
                    opUser,
                    source
            );
        }*/
                // 取消订单业务
                orderCancelService.orderBusHandle(order);

                // 释放锁
                redisTemplate.delete(lockKey);

                // 更新缓存
                cache(order);
                return order;

            } catch (Exception e) {
                // 释放锁
                redisTemplate.delete(lockKey);

                throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "取消失败！未知原因");
            }
        } else {
            try {
                Thread.sleep(100);
            } catch (Exception e) {}
            cancel(orderNo);
        }
        return null;
    }

    @Override
    public void childOrderComplete(String childOrderNo) {
        BsOrderChild orderChild = orderChildService.getDetail(childOrderNo);
        if (orderChild == null) {
            throw ErrorHelp.genException(SysCode.System, ErrorCode.REQ_PARAMS_ERROR, "");
        }
        // 删除缓存
        cacheDelete(orderChild.getOrderNo());

        orderChild.setFinishTime(new Date());
        orderChild.setStatus(OrderChildStatusEnum.status3.getCode());
        orderChildService.editData(orderChild);

        // 查询未完成的子订单数量
        long count = orderChildService.getUndoneChildOrder(orderChild.getOrderNo());
        if (count == 0) {
            BsOrder order = getOrder(orderChild.getOrderNo());
            if (order != null) {
                order.setOrderStatus(OrderStatusEnum.status3.getCode());
                order.setFinishTime(new Date());
                editData(order);
            }
        }
    }

    @Override
    public void orderPaySuccessHandle(OrderModel order) {
        order.setPayTime(order.getPayTime()==null?new Date():order.getPayTime());
        order.setOrderStatus(OrderStatusEnum.status2.getCode());
        editData(order);

        for (BsOrderChild childOrder : order.getOrderChildList()) {
            childOrder.setStatus(OrderChildStatusEnum.status2.getCode());
            orderChildService.editData(childOrder);
        }
        cache(order);

        // 处理业务
        try {
            orderPaySuccessService.orderBusHandle(order);
        } catch (Exception e) {
            System.out.println("业务处理异常");
        }

        try {
            // 查询订单结算
            BsOrderSettle orderSettle = orderSettleService.getData(order.getOrderNo());
            if (orderSettle != null && orderSettle.getLedgerFlag().equals(true)) {
                // 分账业务
                Message<OrderModel> rocketMsg = MessageBuilder.withPayload(order).build();
                rocketMQTemplate.syncSend(OrderTopic.ORDER_TOPIC_PROFIT_SHARING.getTopic(), rocketMsg,1000);
            }
        } catch (Exception e) {
            System.out.println("分账处理异常");
        }
    }

    @Override
    public BsOrder getOrder(String orderNo) {
        BsOrderExample example = new BsOrderExample();
        example.createCriteria().andOrderNoEqualTo(orderNo);
        List<BsOrder> list = orderMapper.selectByExample(example);
        if (!list.isEmpty()) {
            return list.get(0);
        }
        return null;
    }

    @Override
    public OrderModel getDetail(String orderNo) {
        // 获取缓存
        Object cacheObj = redisUtil.get(CACHE_KEY + orderNo);
        if (cacheObj != null) {
            return (OrderModel) cacheObj;
        }
        OrderModel orderModel = new OrderModel();
        BeanUtils.copyProperties(getOrder(orderNo), orderModel);
        // 优惠
        orderModel.setDeduction(orderDeductionService.getOrderDeduction(orderNo));
        // 子订单
        orderModel.setOrderChildList(orderChildService.getOrderChildListByOrderNo(orderNo));
        // 更新缓存
        cache(orderModel);
        return orderModel;
    }

    @Override
    public List<BsOrder> getOrderList(Map<String, Object> param) {
        BsOrderExample example = new BsOrderExample();
        BsOrderExample.Criteria criteria = example.createCriteria();

        if (MapUtils.getLong(param, "userId") != null) {
            criteria.andUserIdEqualTo(MapUtils.getLong(param, "userId"));
        }
        if (StringUtils.isNotBlank(MapUtils.getString(param, "orderNo"))) {
            criteria.andOrderNoLike("%"+MapUtils.getString(param, "orderNo")+"%");
        }
        if (StringUtils.isNotBlank(MapUtils.getString(param, "userPhone"))) {
            criteria.andUserPhoneLike("%"+MapUtils.getString(param, "userPhone")+"%");
        }
        if (MapUtils.getInteger(param, "payChannel") != null) {
            criteria.andPayChannelEqualTo(MapUtils.getInteger(param, "payChannel"));
        }
        if (MapUtils.getInteger(param, "payType") != null) {
            criteria.andPayTypeEqualTo(MapUtils.getInteger(param, "payType"));
        }
        if (MapUtils.getInteger(param, "orderStatus") != null) {
            criteria.andOrderStatusEqualTo(MapUtils.getInteger(param, "orderStatus"));
        }
        if (MapUtils.getLong(param, "createTimeS") != null) {
            criteria.andCreateTimeGreaterThanOrEqualTo(new Date(MapUtils.getLong(param, "createTimeS")));
        }
        if (MapUtils.getLong(param, "createTimeE") != null) {
            criteria.andCreateTimeLessThanOrEqualTo(new Date(MapUtils.getLong(param, "createTimeE")));
        }
        if (MapUtils.getLong(param, "payTimeS") != null) {
            criteria.andPayTimeGreaterThanOrEqualTo(new Date(MapUtils.getLong(param, "payTimeS")));
        }
        if (MapUtils.getLong(param, "payTimeE") != null) {
            criteria.andPayTimeLessThanOrEqualTo(new Date(MapUtils.getLong(param, "payTimeE")));
        }
        if (MapUtils.getLong(param, "finishTimeS") != null) {
            criteria.andFinishTimeGreaterThanOrEqualTo(new Date(MapUtils.getLong(param, "finishTimeS")));
        }
        if (MapUtils.getLong(param, "finishTimeE") != null) {
            criteria.andFinishTimeLessThanOrEqualTo(new Date(MapUtils.getLong(param, "finishTimeE")));
        }
        if (MapUtils.getLong(param, "cancelTimeS") != null) {
            criteria.andCancelTimeGreaterThanOrEqualTo(new Date(MapUtils.getLong(param, "cancelTimeS")));
        }
        if (MapUtils.getLong(param, "cancelTimeE") != null) {
            criteria.andCancelTimeLessThanOrEqualTo(new Date(MapUtils.getLong(param, "cancelTimeE")));
        }

        example.setOrderByClause("create_time desc");
        return orderMapper.selectByExample(example);
    }

    @Override
    public List<Map<String, Object>> getNeedCancelOrderList() {
        return orderMapper.selectNeedCancelOrderList();
    }

}
