package com.fzm.mall.server.front.asset.service.impl;

import com.fzm.mall.server.front.asset.model.dto.OrderMainDTO;
import com.fzm.mall.server.front.asset.model.dto.OrderMainListDTO;
import com.fzm.mall.server.front.asset.model.dto.OrderMainUnitDTO;
import com.fzm.mall.server.front.asset.model.po.OidGidPO;
import com.fzm.mall.server.front.asset.model.vo.good.OrderMainUnitVO;
import com.fzm.mall.server.front.asset.model.vo.good.OrderMainVO;
import com.fzm.mall.server.front.asset.service.OrderMainService;
import com.fzm.mall.server.front.constant.StateConst;
import com.fzm.mall.server.front.goods.mapper.GoodSkuMapper;
import com.fzm.mall.server.front.goods.model.GoodSale;
import com.fzm.mall.server.front.goods.service.IGoodSaleService;
import com.fzm.mall.server.front.mq.MqSend;
import com.fzm.mall.server.front.order.mapper.OrderMapper;
import com.fzm.mall.server.front.order.model.Order;
import com.fzm.mall.server.front.order.model.OrderDetail;
import com.fzm.mall.server.front.order.service.IOrderDetailService;
import com.fzm.mall.server.front.order.service.IOrderService;
import com.fzm.mall.server.front.order.service.IOrderSpuService;
import com.fzm.mall.server.front.redis.GoodRedis;
import com.fzm.mall.server.front.redis.OrderRedis;
import com.fzm.mall.server.front.constant.GoodMainConst;
import com.fzm.mall.server.front.shopping.mapper.UserShoppingCartMapper;
import com.fzm.mall.server.front.util.IdUtil;
import com.fzm.mall.server.front.util.OrderUtil;
import com.fzm.mall.server.front.util.TimeUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

/**
 * @author tdz
 * @date 2021/02/22 11:26
 */
@Slf4j
@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class OrderMainServiceImpl implements OrderMainService {
    private final GoodRedis goodRedis;
    private final OrderRedis orderRedis;
    private final MqSend mqSend;
    private final OrderMapper orderMainDao;
    private final GoodSkuMapper goodSkuMapper;
    private final IGoodSaleService saleService;
    private final IOrderDetailService detailService;
    private final IOrderSpuService orderSpuService;
    private final IOrderService orderService;


    /**
     * 用户下单
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public OrderMainVO order(final String uid, final OrderMainDTO orderMainDTO) {
        // 下单类型
        String type = orderMainDTO.getType();
        List<OrderMainListDTO> orders = orderMainDTO.getOrders();

        List<OrderMainUnitVO> orderVOS = new ArrayList<>(orders.size());
        List<OidGidPO> oidGidPOS = new ArrayList<>(orders.size() * 2);

        // 校验订单数组信息
        Integer ok;
        boolean b;
        for (OrderMainListDTO order : orders) {
            // 订单编号
            String oid = OrderUtil.getOid();
            OidGidPO oidGidPO = new OidGidPO();
            oidGidPO.setOid(oid);

            long timestamp = TimeUtil.timestamp();
            StringBuilder orderName = new StringBuilder();

            List<OrderMainUnitDTO> list = order.getList();
            // 是否接受BTY支付
            Integer acceptBty = 1;
            // 订单总价
            BigDecimal total = new BigDecimal(0);
            // 邮费
            BigDecimal postFee = new BigDecimal(0);
            int size = list.size();
            List<String> gids = new ArrayList<>(size);
            for (int index = 0; index < size; index++) {
                OrderMainUnitDTO unit = list.get(index);
                String gid = unit.getGid();
                String skuId = unit.getSkuId();
                gids.add(gid);
                String coin = unit.getCoin();
                Integer number = Integer.valueOf(unit.getNumber());
                String amount = unit.getAmount();
                String name = unit.getName();
                orderName.append(name).append(";");
                String note = unit.getNote();
                // 查询商品信息
                GoodSale goodSale = saleService.goodSale(gid);
                // 是否接受BTY支付
                Integer otherAcceptBty = goodSale.getAcceptBty();
                acceptBty = acceptBty * otherAcceptBty;
                if (StateConst.POST_TYPE_FREE_INT != goodSale.getPostType()) {
                    int firstNum = goodSale.getFirstNum();
                    BigDecimal firstAmount = goodSale.getFirstAmount();
                    if (firstNum >= number) {
                        postFee = postFee.add(firstAmount);
                    } else {
                        int more = number - firstNum;
                        int secondNum = goodSale.getSecondNum();
                        int sec = more % secondNum == 0 ? more / secondNum : more / secondNum + 1;
                        BigDecimal secondAmount = goodSale.getSecondAmount();
                        postFee = postFee.add(secondAmount).multiply(new BigDecimal(sec)).add(firstAmount);
                    }
                }
                // 不包含邮费总价
                total = total.add(new BigDecimal(amount).multiply(new BigDecimal(number)));

                // 是否拍下减库存  现在都是拍下减库存
                if (GoodMainConst.TYPE_COUNT_ZERO == goodSale.getCountType()) {
                    // 减库存
                    ok = goodSkuMapper.goodStockMinus(gid, coin, number);
                    if (ok == null || ok != 1) {
                        log.info("拍下减库存失败，数据回滚：gid: {}, number: {}", gid, number);
                        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                        return null;
                    }
                }
                // 积分信息
                // 保存订单明细
                OrderDetail orderDetail = new OrderDetail();
                orderDetail.setOid(oid);
                orderDetail.setSkuId(skuId);
                orderDetail.setAmount(new BigDecimal(amount));
                orderDetail.setName(name);
                orderDetail.setCoin(coin);
                orderDetail.setNumber(number);
                orderDetail.setNote(note);
                b = detailService.saveOrUpdate(orderDetail);
                if (!b) {
                    log.info("保存订单明细失败，数据回滚：{} -> {}", gid, coin);
                    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                    return null;
                }
                // 如果是购物车下单，删除购物车，无需判断是否删除成功回滚，不是关键
//                if (GoodMainConst.ORDER_BY_CART.equals(type)) {
//                    userShoppingCartDao.deleteCertByOrder(uid, number, gid, coin, timestamp);
//                }
                // 保存订单快照
                b = orderSpuService.saveSpuSnapshot(gid, String.valueOf(oid));
                if (!b) {
                    log.info("保存订单基础快照失败，数据回滚：{} -> {}", oid, gid);
                    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                    return null;
                }
            }
            oidGidPO.setGids(gids);
            oidGidPOS.add(oidGidPO);
            total = total.add(postFee);
            // TODO 积分抵扣
            // TODO 优惠券抵扣
            // 保存订单
            Order orderMainPO = new Order();
            //OrderMainPO orderMainPO = new OrderMainPO();
            orderMainPO.setUid(uid);
            orderMainPO.setMerchantId(order.getSid());
            orderMainPO.setOid(String.valueOf(oid));
            orderMainPO.setPostFee(postFee);
            orderMainPO.setTotal(total);
            orderMainPO.setDelivery(Integer.parseInt(orderMainDTO.getDelivery()));
            orderMainPO.setUname(orderMainDTO.getUname());
            orderMainPO.setPhone(orderMainDTO.getPhone());
            orderMainPO.setAddress(orderMainDTO.getAddress());
            b = orderService.saveOrUpdate(orderMainPO);
            if (!b) {
                log.info("保存订单失败，数据回滚：{}", orderMainPO);
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                return null;
            }
            //
            OrderMainUnitVO orderMainUnitVO = new OrderMainUnitVO();
            orderMainUnitVO.setOid(String.valueOf(oid));
            orderName.deleteCharAt(orderName.length() - 1);
            orderMainUnitVO.setName(orderName.toString());
            orderMainUnitVO.setTotal(total.toString());
            orderMainUnitVO.setAcceptBty(acceptBty);
            orderMainUnitVO.setCreateTime(timestamp);
            orderVOS.add(orderMainUnitVO);
        }
        if (orderVOS.isEmpty()) {
            return null;
        }
        for (OidGidPO po : oidGidPOS) {
            String oid = po.getOid();
            List<String> gids = po.getGids();
            for (String gid : gids) {
                goodRedis.delSkus(gid);
                orderRedis.setOrderTime(String.valueOf(oid), gid);
            }
            mqSend.sendOrder(oid);
        }
        return OrderMainVO.builder().orders(orderVOS).build();
    }

    /**
     * 撤销订单
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean undo(final String oid) {
        // 先更新订单状态
        long timestamp = TimeUtil.timestamp();
        Integer ok = orderMainDao.orderUndo(oid, timestamp);
        if (ok == null || ok != 1) {
            log.info("更新订单状态失败");
            return false;
        }
        // 恢复商品库存
        List<OrderDetail> listOrderDetail = detailService.listOrderDetail(oid);
        for (OrderDetail po : listOrderDetail) {
            String gid = po.getGoodsId();
            GoodSale goodSale = saleService.goodSale(gid);
            // 是否拍下减库存
            if (GoodMainConst.TYPE_COUNT_ZERO == goodSale.getCountType()) {
                // 恢复库存
                ok = goodSkuMapper.goodRestore(gid, po.getCoin(), po.getNumber().toString());
                if (ok == null || ok != 1) {
                    log.info("恢复商品的库存失败，数据回滚");
                    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                    return false;
                }
                // 删除缓存
                goodRedis.delSkus(gid);
            }
        }
        // 删除缓存
        orderRedis.delOrder(oid);
        return true;
    }

    /**
     * 删除订单
     */
    @Override
    public boolean delete(final String oid) {
        Integer ok = orderMainDao.orderDelete(oid);
        if (ok != null && ok == 1) {
            // 删除缓存
            orderRedis.delOrder(oid);
            return true;
        }
        return false;
    }

}
