package com.qs.mp.channel.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Assert;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qs.mp.admin.domain.TicketBox;
import com.qs.mp.admin.domain.TicketPackage;
import com.qs.mp.admin.domain.param.ChannelOrderCancelParam;
import com.qs.mp.admin.domain.vo.IndexVO;
import com.qs.mp.admin.service.ITicketBoxService;
import com.qs.mp.admin.service.ITicketPackageService;
import com.qs.mp.common.enums.*;
import com.qs.mp.common.utils.DateUtils;
import com.qs.mp.framework.domain.AsyncTask;
import com.qs.mp.framework.service.IAsyncTaskService;
import com.qs.mp.pay.service.IPayOrderService;
import com.qs.mp.pay.service.IWalletService;
import com.qs.mp.user.domain.UserAddr;
import com.qs.mp.channel.domain.ChannelOrder;
import com.qs.mp.channel.domain.ChannelOrderDetail;
import com.qs.mp.channel.domain.ChannelOrderItem;
import com.qs.mp.channel.domain.vo.ChannelCartVO;
import com.qs.mp.channel.domain.vo.ChannelOrderSettleVO;
import com.qs.mp.channel.domain.vo.ChannelOrderVO;
import com.qs.mp.channel.mapper.ChannelOrderMapper;
import com.qs.mp.channel.service.IChannelCartService;
import com.qs.mp.channel.service.IChannelOrderDetailService;
import com.qs.mp.channel.service.IChannelOrderItemService;
import com.qs.mp.channel.service.IChannelOrderService;
import com.qs.mp.common.core.domain.AjaxResult;
import com.qs.mp.common.exception.ServiceException;
import com.qs.mp.common.utils.LogUtil;
import com.qs.mp.pay.domain.PayOrder;
import com.qs.mp.system.service.id.BizIdGenerator;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * <p>
 * 经销商盲票采购订单 服务实现类
 * </p>
 *
 * @author quanshu
 * @since 2022-03-02
 */
@Service
public class ChannelOrderServiceImpl extends
    ServiceImpl<ChannelOrderMapper, ChannelOrder> implements IChannelOrderService {

  protected final Logger logger = LoggerFactory.getLogger(this.getClass().getSimpleName());

  @Autowired
  private BizIdGenerator bizIdGenerator;

  @Autowired
  private ITicketBoxService ticketBoxService;

  @Autowired
  private IChannelOrderItemService channelOrderItemService;

  @Autowired
  private IChannelOrderService channelOrderService;

  @Autowired
  private IChannelCartService channelCartService;

  @Autowired
  private ITicketPackageService ticketPackageService;

  @Autowired
  private IChannelOrderDetailService channelOrderDetailervice;

  @Autowired
  private IWalletService walletService;

  @Autowired
  private IPayOrderService payOrderService;

  @Autowired
  private IAsyncTaskService asyncTaskService;

  @Override
  @Transactional
  public String submitOrder(Long channelId, String memo, ChannelOrderSettleVO orderSettleVO) {
    UserAddr addr = orderSettleVO.getAddr();
    String orderId = bizIdGenerator.newId();
    int prodNum = 0;
    StringBuilder title = new StringBuilder();
    // 创建订单明细
    List<ChannelOrderItem> orderItemList = new ArrayList<>();
    for (ChannelCartVO channelCartVO : orderSettleVO.getItems()) {
      TicketBox ticketBox = ticketBoxService.getById(channelCartVO.getBoxId());
      if (ticketBox.getSalePkgQty() + channelCartVO.getOrderNum() > ticketBox.getPkgQty()) {
        throw new ServiceException(ticketBox.getTitle() + "库存不足，请重新下单");
      }
      ChannelOrderItem item = new ChannelOrderItem();
      item.setOrderId(orderId);
      item.setChannelId(channelId);
      item.setTitle(ticketBox.getTitle());
      item.setPicUrl(ticketBox.getPicUrl());
      item.setBoxId(channelCartVO.getBoxId());
      item.setProperties(ticketBox.getProperties());
      item.setPkgUnit(ticketBox.getPkgUnit());
      item.setFacePrice(ticketBox.getFacePrice());
      item.setOrderNum(channelCartVO.getOrderNum());
      item.setPkgSalePrice(ticketBox.getPkgSalePrice());
      // 预付票处理
      if (Objects.nonNull(orderSettleVO.getType()) && !orderSettleVO.getType().equals(ChannelOrderTypeEnum.RETAIL)) {
          item.setPkgSalePrice(ticketBox.getPkgPrePrice());
      }

      orderItemList.add(item);
      // 累计商品数，拼接标题
      prodNum += channelCartVO.getOrderNum();
      title.append(ticketBox.getTitle()).append(",");
      // 更新盲票组的已销售数和状态，乐观锁
      boolean rst = ticketBoxService.update(new LambdaUpdateWrapper<TicketBox>()
          .set(ticketBox.getSalePkgQty() + channelCartVO.getOrderNum() == ticketBox.getPkgQty(),
              TicketBox::getStatus,
              TicketBoxStatusEnum.PUT_OFF)
          .set(TicketBox::getSalePkgQty, ticketBox.getSalePkgQty() + channelCartVO.getOrderNum())
          .eq(TicketBox::getSalePkgQty, ticketBox.getSalePkgQty())
          .eq(TicketBox::getBoxId, ticketBox.getBoxId()));
      if (!rst) {
        LogUtil.error(logger, "渠道采购票组订单创建时，更新盲票组销量失败。boxId:{0}, saleQty:{1}",
            ticketBox.getBoxId(), ticketBox.getSaleQty());
        throw new ServiceException("渠道采购票组订单创建时，更新盲票组销量失败");
      }
      // 删除购物车
      if (null != channelCartVO.getCartId() && 0 != channelCartVO.getCartId()) {
        channelCartService.removeById(channelCartVO.getCartId());
      }
    }

    // 创建订单
    ChannelOrder channelOrder = new ChannelOrder();
    channelOrder.setOrderId(orderId);
    channelOrder.setChannelId(channelId);
    channelOrder.setTitle(title.substring(0, title.length() > 50 ? 50 : title.length() - 1));
    channelOrder.setOrderAmt(orderSettleVO.getOrderAmt());
    channelOrder.setDiscountAmt(orderSettleVO.getDiscountAmt());
    channelOrder.setFreightAmt(orderSettleVO.getFreightAmt());
    channelOrder.setPayAmt(orderSettleVO.getPayAmt());
    channelOrder.setStatus(ChannelOrderStatusEnum.NOT_PAY);
    channelOrder.setPkgNum(orderSettleVO.getPkgNum());
    channelOrder.setMemo(memo);
    channelOrder.setReceiver(addr.getReceiver());
    channelOrder.setTel(addr.getMobile());
    channelOrder.setProvince(addr.getProvince());
    channelOrder.setCity(addr.getCity());
    channelOrder.setArea(addr.getArea());
    channelOrder.setAddress(addr.getAddr());
    channelOrder.setType(ChannelOrderTypeEnum.getByValue(orderSettleVO.getType()));

    channelOrderService.save(channelOrder);
    channelOrderItemService.saveBatch(orderItemList);
    return channelOrder.getOrderId();
  }

  @Override
  @Transactional(rollbackFor = Exception.class)
  public boolean cancelOrder(Long channelId, String orderId) {
    ChannelOrder channelOrder = channelOrderService.getOne(new LambdaQueryWrapper<ChannelOrder>()
        .eq(ChannelOrder::getChannelId, channelId).eq(ChannelOrder::getOrderId, orderId));
    if (channelOrder.getStatus() != ChannelOrderStatusEnum.NOT_PAY) {
      throw new ServiceException("订单状态异常，不能取消");
    }

    List<ChannelOrderItem> orderItemList = channelOrderItemService.list(
        new LambdaQueryWrapper<ChannelOrderItem>()
            .eq(ChannelOrderItem::getOrderId, orderId));
    for (ChannelOrderItem orderItem : orderItemList) {
      TicketBox ticketBox = ticketBoxService.getById(orderItem.getBoxId());
      // 恢复盲票组的已销售数和状态，乐观锁
        boolean rst = rollbackTicketStatusAndSalePkgQty(orderItem, ticketBox);
        if (!rst) {
        LogUtil.error(logger, "渠道采购票组订单取消时，更新盲票组销量失败。boxId:{0}, saleQty:{1}",
            ticketBox.getBoxId(), ticketBox.getSaleQty());
        throw new ServiceException("渠道采购票组订单取消时，更新盲票组销量失败");
      }
    }
    boolean rst = channelOrderService.update(
        new LambdaUpdateWrapper<ChannelOrder>().set(ChannelOrder::getStatus,
                ChannelOrderStatusEnum.CANCELED)
            .eq(ChannelOrder::getOrderId, orderId)
            .eq(ChannelOrder::getStatus, ChannelOrderStatusEnum.NOT_PAY));
    if (!rst) {
      LogUtil.error(logger, "渠道采购票组订单取消时，更新订单状态失败。orderId:{0}", orderId);
      throw new ServiceException("渠道采购票组订单取消时，更新订单状态失败");
    }
    return true;
  }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean cancelOrderByAdmin(ChannelOrderCancelParam param) {
        ChannelOrder channelOrder = this.getById(param.getOrderId());
        if (Objects.isNull(channelOrder)) {
            throw new ServiceException("订单不存在");
        }
        if (!ChannelOrderStatusEnum.NOT_DELIVER.equals(channelOrder.getStatus())) {
            throw new ServiceException("订单状态异常，不能取消");
        }

        // 更新订单状态
        ChannelOrder channelOrderParam  = new ChannelOrder();
        channelOrderParam.setOrderId(channelOrder.getOrderId());
        channelOrderParam.setStatus(ChannelOrderStatusEnum.CANCELED);
        this.updateById(channelOrderParam);

        // 更新销量
        List<ChannelOrderItem> list = channelOrderItemService.list(new LambdaQueryWrapper<ChannelOrderItem>().eq(ChannelOrderItem::getOrderId, param.getOrderId()));
        if (CollectionUtils.isEmpty(list)) {
            throw new ServiceException("订单商品不存在");
        }
        for (ChannelOrderItem channelOrderItem : list) {
            TicketBox ticketBox = ticketBoxService.getById(channelOrderItem.getBoxId());

            boolean rst = this.rollbackTicketStatusAndSalePkgQty(channelOrderItem, ticketBox);
            if (!rst) {
                throw new ServiceException("操作繁忙,请稍后再试!");
            }
        }


        //退款
        walletService.refund(channelOrder.getOrderId(), channelOrder.getPayAmt(),"经销商取消订单");

        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void confirm(ChannelOrder order) {
        // 更新用户提货订单状态为已完成,并且设置收货时间
        ChannelOrder param = new ChannelOrder();
        param.setOrderId(order.getOrderId());
        param.setStatus(ChannelOrderStatusEnum.FINISHED);
        param.setConfirmTime(new Date());
        boolean rtn = channelOrderService.updateById(param);
        Assert.isTrue(rtn,"更新提货订单状态失败,orderId:{0}", order.getOrderId());

        // 提交异步任务
        AsyncTask asyncTask = new AsyncTask();
        asyncTask.setType(AsyncTaskTypeEnum.CHANNEL_CONFIRM_RECEIPT.getValue());
        asyncTask.setBizId(order.getOrderId());
        Assert.isTrue(asyncTaskService.save(asyncTask),"提交经销商提货订单确认收货任务失败,orderId:{0}", order.getOrderId());
    }

    /**
     * 回滚盲票组销量和状态
     * @param orderItem
     * @param ticketBox
     * @return
     */
    private boolean rollbackTicketStatusAndSalePkgQty(ChannelOrderItem orderItem, TicketBox ticketBox) {
        return ticketBoxService.update(new LambdaUpdateWrapper<TicketBox>()
                .set(
                        ticketBox.getStatus() == TicketBoxStatusEnum.PUT_OFF && ticketBox.getManualOff() != 1,
                        TicketBox::getStatus,
                        TicketBoxStatusEnum.PUT_ON)
                .set(TicketBox::getSalePkgQty, ticketBox.getSalePkgQty() - orderItem.getOrderNum())
                .eq(TicketBox::getSalePkgQty, ticketBox.getSalePkgQty())
                .eq(TicketBox::getBoxId, ticketBox.getBoxId()));
    }

    @Override
  public void paySuccess(PayOrder payOrder) {
    ChannelOrder channelOrder = getById(payOrder.getBizId());
    if (null == channelOrder || channelOrder.getStatus() != ChannelOrderStatusEnum.NOT_PAY) {
      LogUtil.error(logger, "支付回调渠道订单处理，订单状态异常，不是待支付。payOrder:{0}, channelOrder:{1}",
          JSONObject.toJSONString(payOrder), JSONObject.toJSONString(channelOrder));
      throw new ServiceException("支付回调渠道订单处理，订单状态异常，不是待支付。orderId:" + payOrder.getBizId());
    }
    boolean rst = update(
        new LambdaUpdateWrapper<ChannelOrder>().set(ChannelOrder::getStatus,
                ChannelOrderStatusEnum.NOT_DELIVER)
                .set(ChannelOrder::getPayTime, DateUtils.parseDate(payOrder.getCompleteDate()))
            .eq(ChannelOrder::getOrderId, channelOrder.getOrderId())
            .eq(ChannelOrder::getStatus, ChannelOrderStatusEnum.NOT_PAY));
    if (!rst) {
      LogUtil.error(logger, "渠道采购票组订单支付成功时，更新订单状态失败。orderId:{0}",
          channelOrder.getOrderId());
      throw new ServiceException("渠道采购票组订单支付成功时，更新订单状态失败");
    }
  }

	@Override
	@Transactional(rollbackFor = Exception.class)
	public boolean channelOrderShip(ChannelOrder channelOrder, List<String> pkgIdList) {
		if(null == channelOrder || StringUtils.isBlank(channelOrder.getOrderId())) {
			throw new ServiceException("发货订单异常，发货失败");
		}
		List<TicketPackage> ticketPkgList = new ArrayList<TicketPackage>();
		if(null != pkgIdList && pkgIdList.size() > 0) {
			LambdaQueryWrapper<TicketPackage> queryWrapper = new LambdaQueryWrapper<TicketPackage>();
			queryWrapper.eq(TicketPackage::getStatus, TicketPkgStatusEnum.FOR_SALE);
			queryWrapper.in(TicketPackage::getPkgId,  pkgIdList);
			ticketPkgList = ticketPackageService.list(queryWrapper);
			if(null == ticketPkgList || ticketPkgList.size() == 0
					|| ticketPkgList.size() != pkgIdList.size()) {
				throw new ServiceException("发货票包状态异常，发货失败");
			}
		}
		List<ChannelOrderItem> orderItemList = channelOrderItemService.list(
		        new LambdaQueryWrapper<ChannelOrderItem>()
		            .eq(ChannelOrderItem::getOrderId, channelOrder.getOrderId()));
		// 验证发货的盲票包是否与订单中的盲票包数量一致
		if(null == orderItemList || orderItemList.size() == 0 ) {
			throw new ServiceException("订单明细查询异常， 发货失败");
		}
		List<ChannelOrderDetail> detailList = new ArrayList<ChannelOrderDetail>();
		// 验证是否为本订单盲票
		for(TicketPackage ticketPackage:ticketPkgList) {
			if(null != ticketPackage && StringUtils.isNotBlank(ticketPackage.getBoxId())) {
				long num = orderItemList.stream().filter(channelOrderItem -> channelOrderItem.getBoxId().equals(ticketPackage.getBoxId())).count();
				if(num < 1) {
					String msg = "票包"+ticketPackage.getStartSn()+"-" + ticketPackage.getEndSn() +"非本订单盲票";
					throw new ServiceException(msg);
				}
				ChannelOrderDetail channelOrderDetail = new ChannelOrderDetail();
				channelOrderDetail.setBoxId(ticketPackage.getBoxId());
				channelOrderDetail.setPkgId(ticketPackage.getPkgId());
				channelOrderDetail.setOrderId(channelOrder.getOrderId());
				channelOrderDetail.setStartSn(ticketPackage.getStartSn());
				channelOrderDetail.setEndSn(ticketPackage.getEndSn());
				channelOrderDetail.setChannelId(channelOrder.getChannelId());
				detailList.add(channelOrderDetail);
			}
		}
		// 校验数量是否一致
		for(ChannelOrderItem orderItem:orderItemList) {
			if(null != orderItem && StringUtils.isNotBlank(orderItem.getBoxId()) ) {
				long totalNum = ticketPkgList.stream().filter(TicketPackage -> TicketPackage.getBoxId().equals(orderItem.getBoxId())).count();
				if(totalNum != orderItem.getOrderNum()) {
					String msg = "票组"+orderItem.getTitle()+"盲票包" + (totalNum < orderItem.getOrderNum()?"少于":"已超出")+"订单购买的盲票包数量";
					throw new ServiceException(msg);
				}
			}
		}

		boolean res = channelOrderDetailervice.saveBatch(detailList);
		if(!res) {
      throw new ServiceException("保存订单票包发货明细失败");
    }
    // 修改票包已销售状态
    LambdaUpdateWrapper<TicketPackage> updateWrapper = new LambdaUpdateWrapper<TicketPackage>();
    // 如果为预购票,则修改票包的状态
    if (!ChannelOrderTypeEnum.RETAIL.equals(channelOrder.getType())) {
        updateWrapper.set(TicketPackage::getIsPre, 1);
    }
    updateWrapper.set(TicketPackage::getStatus, TicketPkgStatusEnum.SOLD);
    updateWrapper.in(TicketPackage::getPkgId, pkgIdList);
    updateWrapper.eq(TicketPackage::getStatus, TicketPkgStatusEnum.FOR_SALE);
    boolean rtn = ticketPackageService.update(updateWrapper);
    if(!rtn) {
      throw new ServiceException("更新票包发货状态失败");
    }
    // 修改订单信息
    String deliveryFlowId = channelOrder.getDeliveryFlowId();

    // 物流单号为空则表示无需物流发货
    if (StringUtils.isBlank(deliveryFlowId)) {
        channelOrder.setStatus(ChannelOrderStatusEnum.FINISHED);

        // 无需物流插入分佣异步任务
        // 提交异步任务
        AsyncTask asyncTask = new AsyncTask();
        asyncTask.setType(AsyncTaskTypeEnum.CHANNEL_CONFIRM_RECEIPT.getValue());
        asyncTask.setBizId(channelOrder.getOrderId());
        Assert.isTrue(asyncTaskService.save(asyncTask),"提交订单无需物流发货确认收货任务失败,orderId:{0}", channelOrder.getOrderId());

    } else {
        channelOrder.setStatus(ChannelOrderStatusEnum.NOT_CONFIRM);
    }
    boolean updateOrderRtn = updateById(channelOrder);
    if (!updateOrderRtn) {
      throw new ServiceException("更新订单状态失败");
    }
    return true;
	}

	@Override
	public List<ChannelOrderVO> selectChannelOrderVoList(Wrapper<ChannelOrder> wrapper) {
		return getBaseMapper().selectChannelOrderVoList(wrapper);
	}

	@Override
	public int selectChannelOrderCount(Wrapper<ChannelOrder> wrapper) {
		return getBaseMapper().selectChannelOrderCount(wrapper);
	}

    @Override
    public List<IndexVO> selectIndexChannelOrderDailyInfoList(QueryWrapper<ChannelOrder> wrapper) {
        return getBaseMapper().selectIndexChannelOrderDailyInfoList(wrapper);
    }

    @Override
    public int selectPreSaleAmtByQueryWrapper(QueryWrapper<ChannelOrder> channelOrderQueryWrapper) {
        return getBaseMapper().selectPreSaleAmtByQueryWrapper(channelOrderQueryWrapper);
    }
}
