package com.qs.mp.user.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.update.LambdaUpdateWrapper;
import com.qs.mp.admin.domain.Goods;
import com.qs.mp.admin.domain.GoodsSku;
import com.qs.mp.admin.domain.param.UserDeliverOrderShipParam;
import com.qs.mp.admin.service.IGoodsService;
import com.qs.mp.admin.service.IGoodsSkuService;
import com.qs.mp.common.domain.DeliveryCompany;
import com.qs.mp.common.enums.*;
import com.qs.mp.common.exception.ServiceException;
import com.qs.mp.common.service.IDeliveryCompanyService;
import com.qs.mp.common.utils.DateUtils;
import com.qs.mp.common.utils.LogUtil;
import com.qs.mp.common.utils.StringUtils;
import com.qs.mp.pay.domain.PayOrder;
import com.qs.mp.system.service.id.BizIdGenerator;
import com.qs.mp.user.domain.UserAddr;
import com.qs.mp.user.domain.UserDeliverOrder;
import com.qs.mp.user.domain.UserDeliverOrderItem;
import com.qs.mp.user.domain.UserPrizeStorage;
import com.qs.mp.user.domain.UserTicketOrder;
import com.qs.mp.user.domain.excel.DeliverOrderExcel;
import com.qs.mp.user.domain.param.UserDeliverOrderCancelParam;
import com.qs.mp.user.domain.vo.DeliverOrderSettleVO;
import com.qs.mp.user.domain.vo.UserDeliverOrderVO;
import com.qs.mp.user.mapper.UserDeliverOrderMapper;
import com.qs.mp.user.service.IUserDeliverOrderItemService;
import com.qs.mp.user.service.IUserDeliverOrderService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qs.mp.user.service.IUserPrizeStorageService;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;

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;
import org.springframework.util.Assert;

/**
 * <p>
 * 用户提货订单 服务实现类
 * </p>
 *
 * @author quanshu
 * @since 2022-03-07
 */
@Service
public class UserDeliverOrderServiceImpl extends ServiceImpl<UserDeliverOrderMapper, UserDeliverOrder> implements IUserDeliverOrderService {

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

  @Autowired
  private BizIdGenerator bizIdGenerator;

  @Autowired
  private IUserDeliverOrderService userDeliverOrderService;

  @Autowired
  private IUserDeliverOrderItemService userDeliverOrderItemService;

  @Autowired
  private IUserPrizeStorageService userPrizeStorageService;

  @Autowired
  private IGoodsService goodsService;

  @Autowired
  private IGoodsSkuService goodsSkuService;

  @Autowired
  private IDeliveryCompanyService deliveryCompanyService;

  @Override
  @Transactional
  public String submitOrder(Long userId, String memo, DeliverOrderSettleVO orderSettleVO) {




    UserDeliverOrder userDeliverOrder = new UserDeliverOrder();
    userDeliverOrder.setOrderId(bizIdGenerator.newIdWithUidSharding(String.valueOf(userId)));
    userDeliverOrder.setUserId(userId);
    userDeliverOrder.setResource(DeliverOrderResourceEnum.getByValue(orderSettleVO.getResource()));
    UserAddr userAddr = orderSettleVO.getAddr();
    userDeliverOrder.setReceiver(userAddr.getReceiver());
    userDeliverOrder.setTel(userAddr.getMobile());
    userDeliverOrder.setProvince(userAddr.getProvince());
    userDeliverOrder.setCity(userAddr.getCity());
    userDeliverOrder.setArea(userAddr.getArea());
    userDeliverOrder.setAddress(userAddr.getAddr());
    userDeliverOrder.setOrderNum(orderSettleVO.getPrizeList().stream().mapToInt(UserPrizeStorage::getGoodsNum).sum());
    userDeliverOrder.setPayAmt(orderSettleVO.getPayAmt());
    userDeliverOrder.setFreightAmt(orderSettleVO.getFreightAmt());
    userDeliverOrder.setMemo(memo);
    if (orderSettleVO.getPayAmt() > 0) {
      userDeliverOrder.setStatus(DeliverOrderStatusEnum.NOT_PAY);
    } else {
      userDeliverOrder.setStatus(DeliverOrderStatusEnum.NOT_DELIVER);
    }
    save(userDeliverOrder);

    for (UserPrizeStorage prizeStorage : orderSettleVO.getPrizeList()) {
      UserDeliverOrderItem orderItem = new UserDeliverOrderItem();
      orderItem.setItemId(bizIdGenerator.newIdWithUidSharding(String.valueOf(userId)));
      orderItem.setOrderId(userDeliverOrder.getOrderId());
      orderItem.setStorageId(prizeStorage.getStorageId());
      orderItem.setGoodsId(prizeStorage.getGoodsId());
      orderItem.setSkuId(prizeStorage.getSkuId());
      orderItem.setProperties(prizeStorage.getProperties());
      orderItem.setTitle(prizeStorage.getTitle());
      orderItem.setPicUrl(prizeStorage.getPicUrl());
      orderItem.setGoodsNum(prizeStorage.getGoodsNum());
      // 设置供应商id和采购链接
      Goods goods = goodsService.getById(prizeStorage.getGoodsId());
      orderItem.setSupplierId(goods.getSupplierId());
      orderItem.setShoppingLink(goods.getShoppingLink());

      userDeliverOrderItemService.save(orderItem);
        if (DeliverOrderResourceEnum.PAYMENT.getValue().equals(orderSettleVO.getResource())) {
            // 现金购买需要校验和锁库存
            if (Objects.nonNull(prizeStorage.getSkuId()) && prizeStorage.getSkuId() != 0) {
                GoodsSku goodsSku = goodsSkuService.getById(prizeStorage.getSkuId());
                if (goodsSku.getQuantity() < prizeStorage.getGoodsNum()) {
                    throw new ServiceException(prizeStorage.getTitle() + "库存不足,请重新下单");
                }

                // 更新库存
                boolean updateSku = goodsSkuService.update(new LambdaUpdateWrapper<GoodsSku>()
                        .set(GoodsSku::getQuantity, goodsSku.getQuantity() - prizeStorage.getGoodsNum())
                        .set(GoodsSku::getSoldQty, goodsSku.getSoldQty() + prizeStorage.getGoodsNum())
                        .eq(GoodsSku::getSkuId, goodsSku.getSkuId())
                        .eq(GoodsSku::getQuantity, goodsSku.getQuantity())
                        .eq(GoodsSku::getSoldQty, goodsSku.getSoldQty()));
                Assert.isTrue(updateSku, "现金购买商品更新SKU库存失败。goodsId:" + goodsSku.getGoodsId() + ",skuId:" + goodsSku.getSkuId());

            } else {
                if (goods.getQuantity() < prizeStorage.getGoodsNum()) {
                    throw new ServiceException(prizeStorage.getTitle() + "库存不足,请重新下单");
                }
                // 更新库存
                boolean updateGoods = goodsService.update(new LambdaUpdateWrapper<Goods>()
                        .set(goods.getQuantity() - prizeStorage.getGoodsNum() == 0, Goods::getStatus, GoodsStatusEnum.PUT_OFF)
                        .set(Goods::getQuantity, goods.getQuantity() - prizeStorage.getGoodsNum())
                        .set(Goods::getExchangedQty, goods.getExchangedQty() + prizeStorage.getGoodsNum())
                        .eq(Goods::getGoodsId, goods.getGoodsId()).eq(Goods::getQuantity, goods.getQuantity()).eq(Goods::getExchangedQty, goods.getExchangedQty()));
                Assert.isTrue(updateGoods, "现金购买商品更新GOODS库存失败。goodsId:" + goods.getGoodsId() );
            }

        } else {
            boolean rtn = userPrizeStorageService.update(new LambdaUpdateWrapper<UserPrizeStorage>()
                    .set(UserPrizeStorage::getStatus, PrizeStorageStatusEnum.HAS_DISTRIBUTED)
                    .eq(UserPrizeStorage::getStorageId, prizeStorage.getStorageId()));

            Assert.isTrue(rtn, "提交提货订单时，更新状态失败。userDeliverOrder:" + JSONObject.toJSONString(userDeliverOrder));

        }

    }

    return userDeliverOrder.getOrderId();
  }


    @Override
  @Transactional(rollbackFor = Exception.class)
  public boolean cancelOrder(String orderId) {
    UserDeliverOrder userDeliverOrder = getById(orderId);
    if (userDeliverOrder.getStatus() != DeliverOrderStatusEnum.NOT_PAY) {
      LogUtil.warn(logger, "取消提货订单时，订单状态不是待支付，忽略。orderId:{0}, status:{1}",
          orderId, userDeliverOrder.getStatus());
      return false;
    }
    List<UserDeliverOrderItem> orderItemList = userDeliverOrderItemService.list(new LambdaQueryWrapper<UserDeliverOrderItem>()
            .eq(UserDeliverOrderItem::getOrderId, userDeliverOrder.getOrderId()));
    if (DeliverOrderResourceEnum.PAYMENT.equals(userDeliverOrder.getResource())) {
        // 恢复商品库存状态
        for (UserDeliverOrderItem orderItem : orderItemList) {
            if (Objects.nonNull(orderItem.getSkuId()) && orderItem.getSkuId() != 0) {
                GoodsSku goodsSku = goodsSkuService.getById(orderItem.getSkuId());
                if (Objects.nonNull(goodsSku)) {
                    boolean updateSku = goodsSkuService.update(new LambdaUpdateWrapper<GoodsSku>()
                            .set(GoodsSku::getQuantity, goodsSku.getQuantity() + orderItem.getGoodsNum())
                            .set(GoodsSku::getSoldQty, goodsSku.getSoldQty() - orderItem.getGoodsNum())
                            .eq(GoodsSku::getSkuId, goodsSku.getSkuId())
                            .eq(GoodsSku::getGoodsId, goodsSku.getGoodsId())
                            .eq(GoodsSku::getQuantity, goodsSku.getQuantity())
                            .eq(GoodsSku::getSoldQty, goodsSku.getSoldQty()));

                    Assert.isTrue(updateSku, "现金购买商品取消订单更新SKU库存失败。goodsId:" + goodsSku.getGoodsId() + ",skuId:" + goodsSku.getSkuId());
                }
            } else {
                Goods goods = goodsService.getById(orderItem.getGoodsId());
                // 更新库存
                boolean updateGoods = goodsService.update(new LambdaUpdateWrapper<Goods>()
                        .set(Goods::getStatus, GoodsStatusEnum.PUT_ON)
                        .set(Goods::getQuantity, goods.getQuantity() + orderItem.getGoodsNum())
                        .set(Goods::getExchangedQty, goods.getExchangedQty() - orderItem.getGoodsNum())
                        .eq(Goods::getGoodsId, goods.getGoodsId())
                        .eq(Goods::getQuantity, goods.getQuantity())
                        .eq(Goods::getExchangedQty, goods.getExchangedQty()));
                Assert.isTrue(updateGoods, "现金购买商品取消订单更新GOODS库存失败。goodsId:" + goods.getGoodsId() );
            }
        }
    }else {
        // 恢复奖品库状态
        for (UserDeliverOrderItem orderItem : orderItemList) {
            boolean rtn = userPrizeStorageService.update(new LambdaUpdateWrapper<UserPrizeStorage>()
                    .set(UserPrizeStorage::getStatus, PrizeStorageStatusEnum.NOT_DISTRIBUTED)
                    .eq(UserPrizeStorage::getStorageId, orderItem.getStorageId())
                    .eq(UserPrizeStorage::getStatus, PrizeStorageStatusEnum.HAS_DISTRIBUTED));
            Assert.isTrue(rtn, "取消提货订单时，更新奖品库里奖品状态失败。orderItem:" + JSONObject.toJSONString(orderItem));
        }
    }
    userDeliverOrder.setStatus(DeliverOrderStatusEnum.CANCELED);
    boolean updateRst = updateById(userDeliverOrder);
    Assert.isTrue(updateRst, "取消提货订单时，更新提货订单状态失败。userDeliverOrder:" + JSONObject.toJSONString(userDeliverOrder));


    return true;
  }

  @Override
  public boolean paySuccess(PayOrder payOrder) {
    UserDeliverOrder deliverOrder = getById(payOrder.getBizId());
    if (null == deliverOrder || deliverOrder.getStatus() != DeliverOrderStatusEnum.NOT_PAY) {
      LogUtil.error(logger, "支付回调用户提货订单处理，订单状态异常，不是待支付。payOrder:{0}, deliverOrder:{1}",
          JSONObject.toJSONString(payOrder), JSONObject.toJSONString(deliverOrder));
      throw new ServiceException("支付回调用户提货订单处理，订单状态异常，不是待支付。orderId:" + payOrder.getBizId());
    }
    deliverOrder.setStatus(DeliverOrderStatusEnum.NOT_DELIVER);
      deliverOrder.setPayTime(DateUtils.parseDate(payOrder.getCompleteDate()));
    boolean rst = updateById(deliverOrder);
    Assert.isTrue(rst, "支付回调用户提货订单处理，更新订单状态失败，orderId:" + deliverOrder.getOrderId());
    return false;
  }

	@Override
	public List<UserDeliverOrderVO> selectUserDeliverOrderVoList(Wrapper<UserDeliverOrder> wrapper) {
		return getBaseMapper().selectUserDeliverOrderVoList(wrapper);
	}

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

	@Override
	@Transactional(rollbackFor = Exception.class)
	public boolean userDeliverOrderShip(String orderId, List<UserDeliverOrderItem> itemList) {
		boolean res = userDeliverOrderItemService.updateBatchById(itemList);
		if(res) {
			// 检测订单是否全部提货完成
			LambdaQueryWrapper<UserDeliverOrderItem> queryWrapper = new LambdaQueryWrapper<UserDeliverOrderItem>();
			queryWrapper.eq(UserDeliverOrderItem::getOrderId, orderId);
			queryWrapper.isNull(UserDeliverOrderItem::getDeliveryTime);
			int noShipCnt = userDeliverOrderItemService.count(queryWrapper);
			// 部分发货是订单状态仍保留待发货状态， 全部发完的时候再修改订单状态为待收货
			LambdaUpdateWrapper<UserDeliverOrder> updateWrapper = new LambdaUpdateWrapper<UserDeliverOrder>();
			updateWrapper.eq(UserDeliverOrder::getOrderId, orderId);
			if(noShipCnt == 0) {
                // 判断订单是否全部都是无需物流； 有发货时间并且物流单号是空的就是无需物流
                LambdaQueryWrapper<UserDeliverOrderItem> userDeliverOrderItemLambdaQueryWrapper = new LambdaQueryWrapper<>();
                userDeliverOrderItemLambdaQueryWrapper.eq(UserDeliverOrderItem::getOrderId, orderId);
                // 获取订单下所有提货统计
                int orderItemCount = userDeliverOrderItemService.count(userDeliverOrderItemLambdaQueryWrapper);

                userDeliverOrderItemLambdaQueryWrapper.isNotNull(UserDeliverOrderItem::getDeliveryTime);
                userDeliverOrderItemLambdaQueryWrapper.isNull(UserDeliverOrderItem::getDeliveryFlowId);

                // 获取无需物流状态数量
                int noNeedShipCnt = userDeliverOrderItemService.count(userDeliverOrderItemLambdaQueryWrapper);

                // 如果相等则表示所有商品都是无需物流，直接设置订单状态为已完成，并且设置订单的收货时间和发货时间
                if (orderItemCount == noNeedShipCnt) {
                    updateWrapper.set(UserDeliverOrder::getStatus, DeliverOrderStatusEnum.FINISHED);
                    updateWrapper.set(UserDeliverOrder::getDeliveryTime, new Date());
                    updateWrapper.set(UserDeliverOrder::getConfirmTime, new Date());
                } else {
                    // 否则订单状态为待收货,设置发货时间
                    updateWrapper.set(UserDeliverOrder::getDeliveryTime, new Date());
                    updateWrapper.set(UserDeliverOrder::getStatus, DeliverOrderStatusEnum.NOT_CONFIRM);
                }

            }else {
				updateWrapper.set(UserDeliverOrder::getStatus, DeliverOrderStatusEnum.PART_DELIVER);
			}
			return userDeliverOrderService.update(updateWrapper);
		}
		return false;
	}

    @Override
    public String batchShip(List<DeliverOrderExcel> deliverOrderExcelList) {
        // 成功数量
        int successNum = 0;
        // 失败数量
        int failNum = 0;
        // 失败原因
        StringBuilder failSb = new StringBuilder();
        StringBuilder sb = new StringBuilder();
        for (DeliverOrderExcel deliverOrderExcel : deliverOrderExcelList) {
            String failContent = "";
            boolean flag = true;


            DeliveryCompany deliveryCompany = deliveryCompanyService.getOne(new LambdaQueryWrapper<DeliveryCompany>().eq(DeliveryCompany::getCompanyName, deliverOrderExcel.getCompanyName()));
            if (Objects.isNull(deliveryCompany)) {
                flag = false;
                failContent = "物流公司不存在";
            }
            if (flag) {
                if (StringUtils.isBlank(deliverOrderExcel.getDeliveryFlowId())) {
                    flag = false;
                    failContent = "物流单号不存在";
                }
            }

            if (flag) {
                UserDeliverOrder userDeliverOrder = userDeliverOrderService.getById(deliverOrderExcel.getOrderId());
                if (Objects.isNull(userDeliverOrder)) {
                    flag = false;
                    failContent = "订单不存在";
                } else {
                    if (!DeliverOrderStatusEnum.NOT_DELIVER.equals(userDeliverOrder.getStatus()) && !DeliverOrderStatusEnum.PART_DELIVER.equals(userDeliverOrder.getStatus())) {
                        flag = false;
                        failContent = "订单状态不为待发货和部分发货";
                    }
                }
            }

            if (flag) {
                // 校验订单信息
                UserDeliverOrderItem userDeliverOrderItem = userDeliverOrderItemService.getById(deliverOrderExcel.getItemId());
                if (Objects.isNull(userDeliverOrderItem)) {
                    flag = false;
                    failContent = "订单明细ID不存在";
                } else if (Objects.nonNull(userDeliverOrderItem.getDeliveryTime())) {
                    flag = false;
                    failContent = "商品已发货";
                } else {
                    List<UserDeliverOrderItem> itemList = new ArrayList<UserDeliverOrderItem>();
                    // 构建发货参数,进行发货
                    UserDeliverOrderItem item = new UserDeliverOrderItem();
                    // 快递发货，设置物流信息
                    item.setItemId(userDeliverOrderItem.getItemId());
                    item.setDeliveryId(deliveryCompany.getDeliveryId());
                    item.setDeliveryFlowId(deliverOrderExcel.getDeliveryFlowId());
                    item.setDeliveryTime(new Date());
                    itemList.add(item);
                    boolean rtn = this.userDeliverOrderShip(userDeliverOrderItem.getOrderId(), itemList);
                    if (!rtn) {
                        flag = false;
                        failContent = "发货失败,请重试";
                    }
                }
            }

            if (!flag) {
                failNum++;
                failSb.append("订单编号:")
                        .append(deliverOrderExcel.getOrderId())
                        .append("&nbsp;&nbsp;&nbsp;&nbsp;商品ID:")
                        .append(deliverOrderExcel.getGoodsId())
                        .append("&nbsp;&nbsp;&nbsp;&nbsp;商品名称:")
                        .append(deliverOrderExcel.getTitle())
                        .append("&nbsp;&nbsp;&nbsp;&nbsp;发货失败原因:")
                        .append(failContent)
                        .append("<br>");
            } else {
                successNum++;
            }
        }

        sb.append("<div>发货成功:")
                .append(successNum)
                .append("<br>")
                .append("发货失败:")
                .append(failNum)
                .append("<br>")
                .append(failSb)
                .append("</div>");

        return sb.toString();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateShipInfo(UserDeliverOrderShipParam shipParam) {
        Integer deliveryType = shipParam.getDeliveryType();
        boolean res = false;

        for (String itemId : shipParam.getItemIds()) {

            if (DeliverTypeEnum.NO_DELIVER.getValue().equals(deliveryType)) {
                // 无需物流，设置物流信息为空
                res = userDeliverOrderItemService.update(new LambdaUpdateWrapper<UserDeliverOrderItem>()
                        .set(UserDeliverOrderItem::getDeliveryId, null)
                        .set(UserDeliverOrderItem::getDeliveryFlowId, null)
                        .eq(UserDeliverOrderItem::getItemId, itemId));
                // 查询判断是否所有都是无需物流
                LambdaQueryWrapper<UserDeliverOrderItem> userDeliverOrderItemLambdaQueryWrapper = new LambdaQueryWrapper<>();
                userDeliverOrderItemLambdaQueryWrapper.eq(UserDeliverOrderItem::getOrderId, shipParam.getOrderId());
                // 获取订单下所有提货统计数
                int orderItemCount = userDeliverOrderItemService.count(userDeliverOrderItemLambdaQueryWrapper);

                userDeliverOrderItemLambdaQueryWrapper.isNotNull(UserDeliverOrderItem::getDeliveryTime);
                userDeliverOrderItemLambdaQueryWrapper.isNull(UserDeliverOrderItem::getDeliveryFlowId);

                // 获取无需物流状态数量
                int noNeedShipCnt = userDeliverOrderItemService.count(userDeliverOrderItemLambdaQueryWrapper);

                // 如果相等则表示所有商品都是无需物流，直接设置订单状态为已完成，并且设置订单的发货和收货时间
                if (orderItemCount == noNeedShipCnt) {
                    res = userDeliverOrderService.update(new LambdaUpdateWrapper<UserDeliverOrder>()
                            .set(UserDeliverOrder::getStatus, DeliverOrderStatusEnum.FINISHED)
                            .set(UserDeliverOrder::getConfirmTime, new Date())
                            .set(UserDeliverOrder::getDeliveryTime, new Date())
                            .eq(UserDeliverOrder::getOrderId, shipParam.getOrderId()));
                }


            } else if (DeliverTypeEnum.DELIVER.getValue().equals(deliveryType)) {
                // 快递发货，原逻辑
                res = userDeliverOrderItemService.update(new LambdaUpdateWrapper<UserDeliverOrderItem>()
                        .set(UserDeliverOrderItem::getDeliveryId, shipParam.getDeliveryId())
                        .set(UserDeliverOrderItem::getDeliveryFlowId, shipParam.getDeliveryFlowId())
                        .eq(UserDeliverOrderItem::getItemId, itemId));
            }

        }
        return res;
    }

    @Override
	public UserDeliverOrderVO selectUserDeliverOrderVo(String orderId) {
		return getBaseMapper().selectUserDeliverOrderVo(orderId);
	}


}
