package com.fzm.mall.server.admin.order.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fzm.mall.server.admin.config.Redis;
import com.fzm.mall.server.admin.constant.MallResponseError;
import com.fzm.mall.server.admin.exception.MyException;
import com.fzm.mall.server.admin.goods_center.service.ICountService;
import com.fzm.mall.server.admin.goods_center.service.ISkuService;
import com.fzm.mall.server.admin.marketing.model.Coupon;
import com.fzm.mall.server.admin.marketing.service.ICouponService;
import com.fzm.mall.server.admin.order.entity.dto.OrderDTO;
import com.fzm.mall.server.admin.order.mapper.OrderDetailMapper;
import com.fzm.mall.server.admin.order.mapper.OrderMapper;
import com.fzm.mall.server.admin.order.model.*;
import com.fzm.mall.server.admin.order.service.ILogService;
import com.fzm.mall.server.admin.order.service.IOrderService;
import com.fzm.mall.server.admin.order.service.IPayService;
import com.fzm.mall.server.admin.order.service.IRefundService;
import com.fzm.mall.server.admin.user.service.IAssetService;
import com.fzm.mall.server.admin.user.service.IUserCouponService;
import com.fzm.mall.server.admin.util.CopyUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.List;
import java.util.stream.Collectors;

import static com.fzm.mall.server.admin.order.model.Order.ORDER_FRONT_REDIS_KEY;

/**
 * <p>
 * 用户购物订单表 服务实现类
 * </p>
 *
 * @author wulixian
 * @since 2021-03-19
 */
@Service
@Transactional
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements IOrderService {

    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private OrderDetailMapper orderDetailMapper;
    @Autowired
    private ILogService orderLogService;
    @Autowired
    private IAssetService assetService;
    @Autowired
    private ISkuService skuService;
    @Autowired
    private ICountService countService;
    @Autowired
    private ICouponService couponService;
    @Autowired
    private IUserCouponService userCouponService;
    @Autowired
    private IPayService payService;
    @Autowired
    private IRefundService refundService;
    @Autowired
    private Redis redis;

    @Override
    public void consultDiscount(String adminId, String oid, Integer consultDiscountType, BigDecimal consultDiscountAmount, Long updateTime) {
        /**
         * 商品订单操作记录
         */
        OrderLog log = new OrderLog(oid, Order.ORDER_STATE_TO_PAY, OrderLog.ORDER_CONSULT_DISCOUNT + consultDiscountAmount, adminId, "");
        orderLogService.save(log);

        /**
         * 修改应付价格
         */
        Order order = orderMapper.selectOne(new QueryWrapper<Order>().eq("oid", oid).eq("update_time", updateTime));
        order.setConsultDiscountType(consultDiscountType);
        BigDecimal consultDiscountAmountResult = order.getConsultDiscountAmount() == null ? BigDecimal.ZERO.add(consultDiscountAmount)
                : order.getConsultDiscountAmount().add(consultDiscountAmount);
        order.setConsultDiscountAmount(consultDiscountAmountResult);
        BigDecimal amount = order.getAmount().subtract(consultDiscountAmount);
        BigDecimal zero = new BigDecimal(BigInteger.ZERO);
        order.setAmount(amount.compareTo(zero) == 1 ? amount : zero);

        int update = orderMapper.update(order, new UpdateWrapper<Order>().eq("oid", oid).eq("update_time", updateTime));
        if (update == 0) {
            throw new MyException(MallResponseError.UPDATE_FAIL);
        }

        /**
         * 修改支付订单的“待支付金额”
         */
        payService.consultDiscount(oid, consultDiscountAmount);

    }

    @Override
    public void refundExamine(String adminId, String oid, Boolean isApproved, String remark, Long updateTime) {
        /**
         * 删除前台后端对order的缓存
         */
        redis.deleteByMapKey(ORDER_FRONT_REDIS_KEY + oid);

        String operation = OrderLog.ORDER_EXAMINE_FAILED;
        Integer orderState = Order.ORDER_STATE_REFUND_REFUSED;
        Order order = orderMapper.selectOne(new QueryWrapper<Order>().eq("oid", oid));
        List<OrderDetail> orderDetailList = orderDetailMapper.selectList(new QueryWrapper<OrderDetail>().eq("oid", oid));
        if (isApproved) {
            operation = OrderLog.ORDER_EXAMINE_SUCCESS;
            orderState = Order.ORDER_STATE_REFUNDING;

            List<String> goodsIdList = orderDetailList.stream().map(OrderDetail::getGoodsId).collect(Collectors.toList());
            List<Coupon> couponList = couponService.listByOid(order.getOid(), order.getUid(), goodsIdList);

            /**
             * 库存，销量还原
             */
            restoreInventoryAndSales(orderDetailList);

//            /**
//             * 已使用的优惠券还原(2021-06-08，优惠券不退)
//             */
//            restoreCoupon(order.getUid(), couponList);
        }

        /**
         * 商品订单退款-积分还原，商品币还原
         * <p>
         * 审核通过：1.币：根据order_detail的coin和number，将user_asset对应的冻结数量frozen扣除，通过链上方法还给商家
         *         2.积分：根据order_info的amount，将积分还给买家
         * 审核不通过：
         *         1.币：根据order_detail的coin和number，将user_asset对应的冻结数量frozen扣除，加到可用资产amount
         *
         */
        integralDeduction(oid, order.getUid(), order.getAmount(), order.getMerchantId(), orderDetailList, isApproved);

        /**
         * 更改order_refund中的记录状态
         */
        synchroRefundReturnState(oid, isApproved, remark);

        UpdateWrapper<Order> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("oid", oid)
                .eq("update_time", updateTime)
                .set("order_state", orderState)
                .set("v_note", remark);
        int update = orderMapper.update(new Order(), updateWrapper);
        if (update == 0) {
            throw new MyException(MallResponseError.UPDATE_FAIL);
        }

        /**
         * 商品订单操作记录
         */
        OrderLog log = new OrderLog(oid, orderState, operation, adminId, remark);
        orderLogService.save(log);
    }

    /**
     * 退款审核通过，修改“退款表的记录为5 退款完成”
     * 退款审核未通过，修改“退款表的记录为3 审核驳回”
     *
     * @param oid
     */
    private void synchroRefundReturnState(String oid, Boolean isApproved, String remark) {
        Refund refund = new Refund();
        refund.setOid(oid);
        refund.setErrMsg(remark);
        if (isApproved) {
            refund.setReturnState(Refund.REFUND_RETURN_STATE_COMPLETED);
        } else {
            refund.setReturnState(Refund.REFUND_RETURN_STATE_REFUSED);
        }

        UpdateWrapper<Refund> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("oid", oid);
        refundService.update(refund, updateWrapper);
    }

    /**
     * 商品订单退款-积分还原，商品币还原
     * <p>
     * 审核通过：1.币：根据order_detail的coin和number，将user_asset对应的冻结数量frozen扣除，通过链上方法还给商家
     * 2.积分：根据order_info的amount，将积分还给买家
     * 审核不通过：
     * 1.币：根据order_detail的coin和number，将user_asset对应的冻结数量frozen扣除，加到可用资产amount
     *
     * @param uid
     * @param amount
     * @param merchantId
     * @param orderDetailList
     * @param isApproved
     */
    private void integralDeduction(String oid, String uid, BigDecimal amount, String merchantId, List<OrderDetail> orderDetailList, Boolean isApproved) {
        assetService.integralDeduction(oid, uid, amount, merchantId, orderDetailList, isApproved);
    }

    /**
     * 商品订单退款-库存，销量还原
     */
    private void restoreInventoryAndSales(List<OrderDetail> orderDetailList) {
        skuService.restoreInventory(orderDetailList);

        countService.restoreSales(orderDetailList);
    }

    /**
     * 商品订单退款-已使用的优惠券还原
     */
    private void restoreCoupon(String uid, List<Coupon> couponList) {
        userCouponService.restoreCoupon(uid, couponList);
    }

    @Override
    public OrderDTO read(String oid) {
        Order order = orderMapper.read(oid);
        order.listLog(orderLogService, oid);

        List<PayRecord> payRecordList = orderMapper.listPayRecord(oid);
        order.setPayRecordList(payRecordList);
        return CopyUtil.to(order, OrderDTO.class);
    }

    @Override
    public IPage<OrderDTO> page(Page<OrderDTO> page, String uid, String oid, Integer orderState, String merchantId) {
        IPage<OrderDTO> result = orderMapper.page(page, uid, oid, orderState, merchantId);
        result.getRecords().forEach(item -> {
            List<OrderDetail> detailList = orderDetailMapper.selectList(new QueryWrapper<OrderDetail>().eq("oid", item.getOid()));
            List<String> list = detailList.stream().map(OrderDetail::getGoodsId).collect(Collectors.toList());
            item.setGoodsIdList(list);
        });
        return result;
    }
}
