package com.zhongzheng.modules.order.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.zhongzheng.common.exception.CustomException;
import com.zhongzheng.common.utils.DateUtils;
import com.zhongzheng.modules.course.domain.CourseChapterSection;
import com.zhongzheng.modules.exam.domain.ExamNumber;
import com.zhongzheng.modules.goods.domain.Goods;
import com.zhongzheng.modules.goods.service.IGoodsService;
import com.zhongzheng.modules.goods.vo.GoodsVo;
import com.zhongzheng.modules.order.bo.*;
import com.zhongzheng.modules.order.domain.Order;
import com.zhongzheng.modules.order.domain.OrderBillGoods;
import com.zhongzheng.modules.order.domain.OrderBillSheet;
import com.zhongzheng.modules.order.domain.OrderGoods;
import com.zhongzheng.modules.order.mapper.OrderBillSheetMapper;
import com.zhongzheng.modules.order.service.IOrderBillGoodsService;
import com.zhongzheng.modules.order.service.IOrderBillSheetService;
import com.zhongzheng.modules.order.service.IOrderGoodsService;
import com.zhongzheng.modules.order.service.IOrderService;
import com.zhongzheng.modules.order.vo.OrderBillSheetVo;
import com.zhongzheng.modules.order.vo.OrderGoodsVo;
import com.zhongzheng.modules.user.bo.UserExamGoodsQueryBo;
import com.zhongzheng.modules.user.bo.UserExamGoodsSupplementAddBo;
import com.zhongzheng.modules.user.domain.UserExamGoods;
import com.zhongzheng.modules.user.service.IUserExamGoodsService;
import com.zhongzheng.modules.user.service.IUserExamGoodsSupplementService;
import com.zhongzheng.modules.user.vo.UserExamGoodsVo;
import com.zhongzheng.modules.wx.service.IWxPayService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.pagehelper.Page;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 订单计费单Service业务层处理
 *
 * @author hjl
 * @date 2021-11-09
 */
@Service
public class OrderBillSheetServiceImpl extends ServiceImpl<OrderBillSheetMapper, OrderBillSheet> implements IOrderBillSheetService {

    @Autowired
    private IOrderBillGoodsService iOrderBillGoodsService;

    @Autowired
    private IOrderGoodsService iOrderGoodsService;

    @Autowired
    private IOrderService iOrderService;

    @Autowired
    private IWxPayService iWxPayService;

    @Autowired
    private IUserExamGoodsService userExamGoodsService;

    @Autowired
    private IUserExamGoodsSupplementService userExamGoodsSupplementService;


    @Autowired
    private IGoodsService iGoodsService;

    private Map<String, List<OrderGoodsVo>> orderGoodsList = new HashMap<>();

    @Override
    public OrderBillSheetVo queryById(Long sheetId){
        OrderBillSheet db = this.baseMapper.selectById(sheetId);
        return BeanUtil.toBean(db, OrderBillSheetVo.class);
    }

    @Override
    public OrderBillSheetVo queryBySn(String sheetSn) {
        OrderBillSheet db = getOne(new LambdaQueryWrapper<OrderBillSheet>().eq(OrderBillSheet::getSheetSn,sheetSn));
        return BeanUtil.toBean(db, OrderBillSheetVo.class);
    }


    @Override
    public List<OrderBillSheetVo> queryList(OrderBillSheetQueryBo bo) {
        LambdaQueryWrapper<OrderBillSheet> lqw = Wrappers.lambdaQuery();
        lqw.eq(StrUtil.isNotBlank(bo.getPayer()), OrderBillSheet::getPayer, bo.getPayer());
        lqw.eq(StrUtil.isNotBlank(bo.getPayerTel()), OrderBillSheet::getPayerTel, bo.getPayerTel());
        lqw.eq(StrUtil.isNotBlank(bo.getPayType()), OrderBillSheet::getPayType, bo.getPayType());
        lqw.eq(StrUtil.isNotBlank(bo.getPayAccount()), OrderBillSheet::getPayAccount, bo.getPayAccount());
        lqw.eq(StrUtil.isNotBlank(bo.getPayee()), OrderBillSheet::getPayee, bo.getPayee());
        lqw.eq(StrUtil.isNotBlank(bo.getCollectionAccount()), OrderBillSheet::getCollectionAccount, bo.getCollectionAccount());
        lqw.eq(StrUtil.isNotBlank(bo.getPayChannel()), OrderBillSheet::getPayChannel, bo.getPayChannel());
        lqw.eq(StrUtil.isNotBlank(bo.getPosNumber()), OrderBillSheet::getPosNumber, bo.getPosNumber());
        lqw.eq(StrUtil.isNotBlank(bo.getVoucherNo()), OrderBillSheet::getVoucherNo, bo.getVoucherNo());
        lqw.eq(StrUtil.isNotBlank(bo.getRefNo()), OrderBillSheet::getRefNo, bo.getRefNo());
        lqw.eq(StrUtil.isNotBlank(bo.getSheetSn()), OrderBillSheet::getSheetSn, bo.getSheetSn());
        return entity2Vo(this.list(lqw));
    }

    /**
    * 实体类转化成视图对象
    *
    * @param collection 实体类集合
    * @return
    */
    private List<OrderBillSheetVo> entity2Vo(Collection<OrderBillSheet> collection) {
        List<OrderBillSheetVo> voList = collection.stream()
                .map(any -> BeanUtil.toBean(any, OrderBillSheetVo.class))
                .collect(Collectors.toList());
        if (collection instanceof Page) {
            Page<OrderBillSheet> page = (Page<OrderBillSheet>)collection;
            Page<OrderBillSheetVo> pageVo = new Page<>();
            BeanUtil.copyProperties(page,pageVo);
            pageVo.addAll(voList);
            voList = pageVo;
        }
        return voList;
    }

    @Override
    public Boolean insertByAddBo(OrderBillSheetAddBo bo) {
        OrderBillSheet add = BeanUtil.toBean(bo, OrderBillSheet.class);
        validEntityBeforeSave(add);
        add.setCreateTime(DateUtils.getNowTime());
        add.setUpdateTime(DateUtils.getNowTime());
        return this.save(add);
    }

    @Override
    public Boolean updateByEditBo(OrderBillSheetEditBo bo) {
        OrderBillSheet update = BeanUtil.toBean(bo, OrderBillSheet.class);
        validEntityBeforeSave(update);
        update.setUpdateTime(DateUtils.getNowTime());
        return this.updateById(update);
    }

    /**
     * 保存前的数据校验
     *
     * @param entity 实体类数据
     */
    private void validEntityBeforeSave(OrderBillSheet entity){
        //TODO 做一些数据校验,如唯一约束
    }

    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if(isValid){
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return this.removeByIds(ids);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> placeBillOrder(OrderBillSheetAddBo bo) {
        List<OrderBillGoodsAddBo> goodsList = bo.getGoodsList();
        if(goodsList==null||goodsList.size()<1){
            throw new CustomException("商品列表为空");
        }
        OrderBillSheet add = BeanUtil.toBean(bo, OrderBillSheet.class);
        validEntityBeforeSave(add);
        add.setCreateTime(DateUtils.getNowTime());
        add.setUpdateTime(DateUtils.getNowTime());
        //计费订单号
        String sheet_no = DateUtils.getDateOrderSn();
        add.setSheetSn(sheet_no);
        //生成订单
        Collection<OrderBillGoods> coll = new HashSet<>();
        for (OrderBillGoodsAddBo g : goodsList) {
            //计费单商品
            OrderBillGoods orderGoods = BeanUtil.toBean(g, OrderBillGoods.class);
            orderGoods.setOrderSn(g.getOrderSn());
            orderGoods.setSheetSn(sheet_no);
            orderGoods.setCreateTime(DateUtils.getNowTime());
            orderGoods.setUpdateTime(DateUtils.getNowTime());
            coll.add(orderGoods);
            if(orderGoods.getAmount().compareTo(BigDecimal.ZERO)!=1){
                throw new CustomException("已收费用必须大于0");
            }
            //订单商品
            OrderGoods goods = iOrderGoodsService.getOne(new LambdaQueryWrapper<OrderGoods>().eq(OrderGoods::getOrderSn, g.getOrderSn()).eq(OrderGoods::getGoodsId,g.getGoodsId()));
            if(goods==null){
                throw new CustomException("订单商品错误");
            }
            Order order = iOrderService.getOne(new LambdaQueryWrapper<Order>().eq(Order::getOrderSn, g.getOrderSn()));
            if(order==null){
                throw new CustomException("订单错误");
            }
            //计费单已收费用累加
            goods.setGoodsReceived(goods.getGoodsReceived().add(orderGoods.getAmount()));
            if(goods.getGoodsRealPrice().compareTo(goods.getGoodsReceived()) == -1){
                throw new CustomException("已收费用超出成交价");
            }
            else if(goods.getGoodsRealPrice().compareTo(goods.getGoodsReceived()) == 0){
                //完全收费
                goods.setPayStatus(OrderGoods.PAY_FULL);
                order = this.updateOrderGoodsPAY_FULL(order,goods.getGoodsId());  //订单支付状态判断是否更新为全部支付
            }
            else{
                //部分收费
                goods.setPayStatus(OrderGoods.PAY_PART);
                order.setOrderStatus(Order.PAY_PART);  //订单支付状态改为部分支付
            }
            iWxPayService.joinLockGrade(order.getOrderSn(),goods.getGoodsId(),goods.getOrderGoodsId());
            order.setStatus(1);//订单生效
            order.setUpdateTime(DateUtils.getNowTime());
            iOrderService.updateById(order);
            goods.setUpdateTime(DateUtils.getNowTime());
            iOrderGoodsService.updateById(goods);
            updateUserExamGoods(goods,order);
        }
        iOrderBillGoodsService.saveBatch(coll);
        this.save(add);
        Map<String, Object> result = new HashMap<>();
        result.put("sheetId",add.getSheetId());
        result.put("sheetSn",sheet_no);
        return result;
    }
    private void updateUserExamGoods(OrderGoods g,Order order) {
        GoodsVo goodsVo = iGoodsService.queryById(g.getGoodsId());
        //添加商品考试次数和补考次数
        if (goodsVo.getGoodsType().equals(1)){
            if (userExamGoodsService.queryExamGoods(goodsVo.getGoodsId(),order.getUserId()) < 1){
                ExamNumber examNumber = userExamGoodsService.queryExam(goodsVo.getGoodsId());
                if (examNumber != null) {
                    UserExamGoods add = new UserExamGoods();
                    add.setGoodsId(g.getGoodsId());
                    add.setUserId(order.getUserId());
                    add.setExamNumber(examNumber.getExamNumber());
                    add.setDoNumber(examNumber.getDoNumber());
                    add.setCreateTime(DateUtils.getNowTime());
                    add.setUpdateTime(DateUtils.getNowTime());
                    userExamGoodsService.save(add);
                    UserExamGoodsSupplementAddBo userExamGoodsSupplementAddBo = new UserExamGoodsSupplementAddBo();
                    userExamGoodsSupplementAddBo.setGoodsId(goodsVo.getGoodsId());
                    userExamGoodsSupplementAddBo.setUserExamGoodsId(add.getUserExamGoodsId());
                    userExamGoodsSupplementAddBo.setExamNumber(examNumber.getExamNumber());
                    userExamGoodsSupplementAddBo.setDoNumber(examNumber.getDoNumber());
                    userExamGoodsSupplementAddBo.setStatus(3);
                    userExamGoodsSupplementService.insertByAddBo(userExamGoodsSupplementAddBo);
                }
            }
        }
        //增加前培次数
        if (goodsVo.getGoodsType().equals(4)){
            UserExamGoodsQueryBo userExamGoodsQueryBo = new UserExamGoodsQueryBo();
            userExamGoodsQueryBo.setUserId(order.getUserId());
            userExamGoodsQueryBo.setGoodsId(goodsVo.getMakeGoodsId());
            List<UserExamGoodsVo> userExamGoodsVos = userExamGoodsService.queryList(userExamGoodsQueryBo);
            if (!CollectionUtils.isEmpty(userExamGoodsVos)){
                UserExamGoodsVo userExamGoodsVo = userExamGoodsVos.get(0);
                UserExamGoodsSupplementAddBo userExamGoodsSupplementAddBo = new UserExamGoodsSupplementAddBo();
                userExamGoodsSupplementAddBo.setGoodsId(goodsVo.getGoodsId());
                userExamGoodsSupplementAddBo.setUserExamGoodsId(userExamGoodsVo.getUserExamGoodsId());
                userExamGoodsSupplementAddBo.setDoNumber(goodsVo.getStudyCount());
                userExamGoodsSupplementAddBo.setStatus(2);
                userExamGoodsSupplementService.insertByAddBo(userExamGoodsSupplementAddBo);
                UserExamGoods userExamGoods = new UserExamGoods();
                userExamGoods.setUserExamGoodsId(userExamGoodsVo.getUserExamGoodsId());
                userExamGoods.setDoNumber(userExamGoodsVo.getDoNumber()+goodsVo.getStudyCount());
                userExamGoodsService.updateById(userExamGoods);
            }
        }
        //增加考试次数
        if (goodsVo.getGoodsType().equals(3)){
            UserExamGoodsQueryBo userExamGoodsQueryBo = new UserExamGoodsQueryBo();
            userExamGoodsQueryBo.setUserId(order.getUserId());
            userExamGoodsQueryBo.setGoodsId(goodsVo.getMakeGoodsId());
            List<UserExamGoodsVo> userExamGoodsVos = userExamGoodsService.queryList(userExamGoodsQueryBo);
            if (!CollectionUtils.isEmpty(userExamGoodsVos)){
                UserExamGoodsVo userExamGoodsVo = userExamGoodsVos.get(0);
                UserExamGoodsSupplementAddBo userExamGoodsSupplementAddBo = new UserExamGoodsSupplementAddBo();
                userExamGoodsSupplementAddBo.setGoodsId(goodsVo.getGoodsId());
                userExamGoodsSupplementAddBo.setUserExamGoodsId(userExamGoodsVo.getUserExamGoodsId());
                userExamGoodsSupplementAddBo.setExamNumber(goodsVo.getStudyCount());
                userExamGoodsSupplementAddBo.setStatus(1);
                userExamGoodsSupplementService.insertByAddBo(userExamGoodsSupplementAddBo);
                UserExamGoods userExamGoods = new UserExamGoods();
                userExamGoods.setUserExamGoodsId(userExamGoodsVo.getUserExamGoodsId());
                userExamGoods.setExamNumber(userExamGoodsVo.getExamNumber()+goodsVo.getStudyCount());
                userExamGoodsService.updateById(userExamGoods);
            }
        }
    }

    /**
     * 修改订单商品支付状态为完全支付
     * @param order
     * @param goodsId
     * @return
     */
    public Order updateOrderGoodsPAY_FULL( Order order,Long goodsId) {
        String orderSn = order.getOrderSn();
        List<OrderGoodsVo> orderGoodsVoList = null;
        if(orderGoodsList.containsKey(orderSn)){
            orderGoodsVoList =  orderGoodsList.get(orderSn);
        }else{
            OrderGoodsQueryBo bo = new OrderGoodsQueryBo();
            bo.setOrderSn(orderSn);
            orderGoodsVoList = iOrderGoodsService.selectList(bo);
            orderGoodsList.put(orderSn,orderGoodsVoList);
        }
        boolean isAllPayFull = true;//是否全部都是完全支付状态
        for (OrderGoodsVo g : orderGoodsVoList) {
            if(g.getGoodsId().equals(goodsId)){
                //临时设置为完全收费
                g.setPayStatus(OrderGoods.PAY_FULL);
            }
            if(!(g.getPayStatus().equals(OrderGoods.PAY_FULL))){
                isAllPayFull = false;
            }
        }
       if(isAllPayFull){
           order.setOrderStatus(Order.PAY_FULL);
       }
        return order;
    }
}
