package com.ym.mec.biz.service.impl;


import com.alibaba.fastjson.JSONObject;
import com.ym.mec.biz.dal.dao.*;
import com.ym.mec.biz.dal.entity.*;
import com.ym.mec.biz.dal.enums.*;
import com.ym.mec.biz.service.*;
import com.ym.mec.common.dal.BaseDAO;
import com.ym.mec.common.service.impl.BaseServiceImpl;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;

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

@Service
public class SellOrderServiceImpl extends BaseServiceImpl<Integer, SellOrder> implements SellOrderService {
    @Autowired
    private SellOrderDao sellOrderDao;
    @Autowired
    private GoodsDao goodsDao;
    @Autowired
    private StudentPaymentOrderDao studentPaymentOrderDao;
    @Autowired
    private MusicGroupDao musicGroupDao;
    @Autowired
    private SysPaymentConfigService sysPaymentConfigService;
    @Autowired
    private SysUserCashAccountService sysUserCashAccountService;
    @Autowired
    private GoodsService goodsService;
    @Autowired
    private StudentPaymentOrderDetailDao studentPaymentOrderDetailDao;
    @Autowired
    private SporadicChargeInfoDao sporadicChargeInfoDao;
    @Autowired
    private StudentRepairDao studentRepairDao;

    @Override
    public BaseDAO<Integer, SellOrder> getDAO() {
        return sellOrderDao;
    }


    @Override
    @Transactional(rollbackFor = Exception.class, isolation = Isolation.READ_COMMITTED)
    public List<SellOrder> addSellOrder(Long orderId, String musicGroupId, List<Integer> goodsIds, BigDecimal totalAmount, BigDecimal balance) {
        if (goodsIds == null || goodsIds.size() <= 0) {
            return null;
        }
        if (balance == null) {
            balance = BigDecimal.ZERO;
        }
        StudentPaymentOrder order = studentPaymentOrderDao.get(orderId);
        MusicGroup musicGroup = new MusicGroup();
        if (StringUtils.isNotBlank(musicGroupId)) {
            musicGroup = musicGroupDao.get(musicGroupId);
        }
        int goodsNum = goodsIds.size();
        BigDecimal goodsTotalPrice = BigDecimal.ZERO;
        List<Goods> goodies = goodsDao.getGoodies(goodsIds);
        int i = 1;
        for (Integer goodsId : goodsIds) {
            for (Goods goods : goodies) {
                if (goods.getId().equals(goodsId)) {
                    goodsTotalPrice = goodsTotalPrice.add(goods.getDiscountPrice());
                    break;
                }
            }
        }

        BigDecimal hasRouteBalance = BigDecimal.ZERO;
        BigDecimal goodsTotalBalance = goodsTotalPrice.multiply(balance).divide(totalAmount, 2, BigDecimal.ROUND_DOWN);
        AccountType accountType = sysPaymentConfigService.checkAccountType(PaymentChannelEnum.valueOf(order.getPaymentChannel()), order.getMerNos());

        List<SellOrder> sellOrderList = goodsService.subtractStock(goodsIds, accountType);

        for (Integer goodsId : goodsIds) {
            BigDecimal goodsPrice = BigDecimal.ZERO;
            Goods nowGoods = new Goods();
            for (Goods goods : goodies) {
                if (goods.getId().equals(goodsId)) {
                    nowGoods = goods;
                    break;
                }
            }
            goodsPrice = nowGoods.getDiscountPrice();

            BigDecimal goodsBalance = goodsTotalBalance.multiply(goodsPrice).divide(goodsTotalPrice, 2, BigDecimal.ROUND_DOWN);
            if (i == goodsNum) {
                goodsBalance = goodsTotalBalance.subtract(hasRouteBalance);
            }
            hasRouteBalance = hasRouteBalance.add(goodsBalance);
            i++;

            int complementGoodsNum = nowGoods.getComplementGoodsIdList() == null ? 1 : nowGoods.getComplementGoodsIdList().split(",").length;
            BigDecimal complementPrice = nowGoods.getDiscountPrice();
            Map<Integer, BigDecimal> complementGoodsPrice = new HashMap<>();
            complementGoodsPrice.put(nowGoods.getId(), nowGoods.getDiscountPrice());
            if (nowGoods.getComplementGoodsIdList() != null) {
                List<Goods> complementGoodies = goodsDao.findGoodsByIds(nowGoods.getComplementGoodsIdList());
                complementGoodsPrice = complementGoodies.stream().collect(Collectors.toMap(Goods::getId, Goods::getDiscountPrice));
                complementPrice = complementGoodies.stream().map(Goods::getDiscountPrice).reduce(BigDecimal.ZERO, BigDecimal::add);
            }

            BigDecimal hasRouteSellOrderActualAmount = BigDecimal.ZERO;
            BigDecimal hasRouteSellOrderBalance = BigDecimal.ZERO;
            for (SellOrder sellOrder : sellOrderList) {
                if (!goodsId.equals(sellOrder.getParentGoodsId()) && !goodsId.equals(sellOrder.getGoodsId())) {
                    continue;
                }
                if (sellOrder.getHasRoute()) {
                    continue;
                }
                BigDecimal sellOrderActualAmount = BigDecimal.ZERO;
                BigDecimal sellOrderBalance = BigDecimal.ZERO;
                if (complementPrice.compareTo(BigDecimal.ZERO) > 0) {
                    sellOrderActualAmount = complementGoodsPrice.get(sellOrder.getGoodsId()).multiply(new BigDecimal(sellOrder.getNum())).multiply(goodsPrice).divide(complementPrice, 2, BigDecimal.ROUND_DOWN);
                    sellOrderBalance = complementGoodsPrice.get(sellOrder.getGoodsId()).multiply(new BigDecimal(sellOrder.getNum())).multiply(goodsBalance).divide(complementPrice, 2, BigDecimal.ROUND_DOWN);
                }

                complementGoodsNum = complementGoodsNum - sellOrder.getNum();
                if (complementGoodsNum <= 0) {
                    sellOrderActualAmount = goodsPrice.subtract(hasRouteSellOrderActualAmount);
                    sellOrderBalance = goodsBalance.subtract(hasRouteSellOrderBalance);
                }
                hasRouteSellOrderActualAmount = hasRouteSellOrderActualAmount.add(sellOrderActualAmount);
                hasRouteSellOrderBalance = hasRouteSellOrderBalance.add(sellOrderBalance);

                sellOrder.setExpectAmount(sellOrderActualAmount);
                sellOrder.setBalanceAmount(sellOrderBalance);
                sellOrder.setActualAmount(sellOrderActualAmount.subtract(sellOrderBalance));
                sellOrder.setOrganId(order.getOrganId());
                sellOrder.setCooperationOrganId(musicGroup.getCooperationOrganId());
                sellOrder.setTransNo(order.getTransNo());
                sellOrder.setOrderId(order.getId());
                sellOrder.setOrderNo(order.getOrderNo());
                sellOrder.setUserId(order.getUserId());
                sellOrder.setPaymentChannel(order.getPaymentChannel());
                sellOrder.setMerNo(order.getMerNos());
                sellOrder.setSellTime(order.getCreateTime());
                sellOrder.setCreateIme(new Date());
                sellOrder.setUpdateTime(new Date());
                if (nowGoods.getType().equals(GoodsType.INSTRUMENT)) {
                    sellOrder.setType(SellTypeEnum.INSTRUMENT);
                } else if (nowGoods.getType().equals(GoodsType.ACCESSORIES)) {
                    sellOrder.setType(SellTypeEnum.ACCESSORIES);
                } else {
                    sellOrder.setType(SellTypeEnum.OTHER);
                }
                sellOrder.setHasRoute(true);
                if (complementGoodsNum <= 0) {
                    break;
                }
            }
        }
        sellOrderDao.batchInsert(sellOrderList);
        return sellOrderList;
    }

    @Override
    @Transactional(rollbackFor = Exception.class, isolation = Isolation.READ_COMMITTED)
    public List<SellOrder> addOrderDetail2SellOrder(List<StudentPaymentOrderDetail> orderDetails, StudentPaymentOrder studentPaymentOrder, MusicGroup musicGroup) {
        List<SellOrder> sellOrders = new ArrayList<>();
        //总余额支付
        BigDecimal totalBalance = studentPaymentOrder.getBalancePaymentAmount() != null ? studentPaymentOrder.getBalancePaymentAmount() : BigDecimal.ZERO;
        //总价格
        BigDecimal totalPrice = studentPaymentOrder.getExpectAmount();
        //商品总付款
        BigDecimal detailTotalPrice = orderDetails.stream().map(StudentPaymentOrderDetail::getPrice).reduce(BigDecimal.ZERO, BigDecimal::add);
        //商品销售占的余额
        BigDecimal detailTotalBalance = detailTotalPrice.compareTo(BigDecimal.ZERO) <= 0 ? BigDecimal.ZERO :
                detailTotalPrice.multiply(totalBalance).divide(totalPrice, 2, BigDecimal.ROUND_DOWN);

        int i = 1;
        BigDecimal detailRouteBalance = BigDecimal.ZERO;

        AccountType accountType = sysPaymentConfigService.checkAccountType(PaymentChannelEnum.valueOf(studentPaymentOrder.getPaymentChannel()), studentPaymentOrder.getMerNos());

        for (StudentPaymentOrderDetail orderDetail : orderDetails) {
            BigDecimal detailBalance = orderDetail.getPrice().compareTo(BigDecimal.ZERO) <= 0 ? BigDecimal.ZERO :
                    orderDetail.getPrice().multiply(detailTotalBalance).divide(detailTotalPrice, 2, BigDecimal.ROUND_DOWN);
            if (i == orderDetails.size()) {
                detailBalance = detailTotalBalance.subtract(detailRouteBalance);
            }
            detailRouteBalance = detailRouteBalance.add(detailBalance);
            i++;

            BigDecimal goodsTotalPrice = orderDetail.getGoodsList().stream().map(Goods::getGroupPurchasePrice).reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal routePrice = BigDecimal.ZERO;
            BigDecimal routeBalance = BigDecimal.ZERO;
            int j = 1;

            List<Integer> goodsIds = orderDetail.getGoodsList().stream().map(Goods::getId).collect(Collectors.toList());
            List<SellOrder> sellOrderList = goodsService.subtractStock(goodsIds, accountType);
            for (Goods goods : orderDetail.getGoodsList()) {
                BigDecimal expectAmount = BigDecimal.ZERO;
                BigDecimal balance = BigDecimal.ZERO;
                if (goodsTotalPrice.compareTo(BigDecimal.ZERO) > 0) {
                    expectAmount = goods.getGroupPurchasePrice().multiply(orderDetail.getPrice()).divide(goodsTotalPrice, 2, BigDecimal.ROUND_DOWN);
                    balance = goods.getGroupPurchasePrice().multiply(detailBalance).divide(goodsTotalPrice, 2, BigDecimal.ROUND_DOWN);
                }
                if (j == orderDetail.getGoodsList().size()) {
                    expectAmount = orderDetail.getPrice().subtract(routePrice);
                    balance = detailBalance.subtract(routeBalance);
                }
                routePrice = routePrice.add(expectAmount);
                routeBalance = routeBalance.add(balance);
                j++;

                int complementGoodsNum = goods.getComplementGoodsIdList() == null ? 1 : goods.getComplementGoodsIdList().split(",").length;
                BigDecimal complementPrice = goods.getGroupPurchasePrice();
                Map<Integer, BigDecimal> complementGoodsPrice = new HashMap<>();
                complementGoodsPrice.put(goods.getId(), goods.getGroupPurchasePrice());
                if (goods.getComplementGoodsIdList() != null) {
                    List<Goods> complementGoodies = goodsDao.findGoodsByIds(goods.getComplementGoodsIdList());
                    complementGoodsPrice = complementGoodies.stream().collect(Collectors.toMap(Goods::getId, Goods::getGroupPurchasePrice));
                    complementPrice = complementGoodies.stream().map(Goods::getGroupPurchasePrice).reduce(BigDecimal.ZERO, BigDecimal::add);
                }

                BigDecimal hasRouteSellOrderExpectAmount = BigDecimal.ZERO;
                BigDecimal hasRouteSellOrderBalance = BigDecimal.ZERO;
                for (SellOrder sellOrder : sellOrderList) {
                    if (!goods.getId().equals(sellOrder.getParentGoodsId()) && !goods.getId().equals(sellOrder.getGoodsId())) {
                        continue;
                    }
                    if (sellOrder.getHasRoute()) {
                        continue;
                    }
                    BigDecimal sellOrderExpectAmount = BigDecimal.ZERO;
                    BigDecimal sellOrderBalance = BigDecimal.ZERO;
                    if (complementPrice.compareTo(BigDecimal.ZERO) > 0) {
                        sellOrderExpectAmount = complementGoodsPrice.get(sellOrder.getGoodsId()).multiply(new BigDecimal(sellOrder.getNum())).multiply(expectAmount).divide(complementPrice, 2, BigDecimal.ROUND_DOWN);
                        sellOrderBalance = complementGoodsPrice.get(sellOrder.getGoodsId()).multiply(new BigDecimal(sellOrder.getNum())).multiply(balance).divide(complementPrice, 2, BigDecimal.ROUND_DOWN);
                    }
                    complementGoodsNum = complementGoodsNum - sellOrder.getNum();
                    if (complementGoodsNum <= 0) {
                        sellOrderExpectAmount = expectAmount.subtract(hasRouteSellOrderExpectAmount);
                        sellOrderBalance = balance.subtract(hasRouteSellOrderBalance);
                    }
                    hasRouteSellOrderExpectAmount = hasRouteSellOrderExpectAmount.add(sellOrderExpectAmount);
                    hasRouteSellOrderBalance = hasRouteSellOrderBalance.add(sellOrderBalance);

                    sellOrder.setOrganId(studentPaymentOrder.getOrganId());
                    sellOrder.setTransNo(studentPaymentOrder.getTransNo());
                    sellOrder.setOrderId(studentPaymentOrder.getId());
                    if (musicGroup != null) {
                        sellOrder.setCooperationOrganId(musicGroup.getCooperationOrganId());
                        sellOrder.setEduTeacherId(musicGroup.getEducationalTeacherId());
                    }
                    sellOrder.setOrderNo(studentPaymentOrder.getOrderNo());
                    sellOrder.setActualAmount(sellOrderExpectAmount.subtract(sellOrderBalance));
                    sellOrder.setBalanceAmount(sellOrderBalance);
                    sellOrder.setExpectAmount(sellOrderExpectAmount);
                    sellOrder.setNum(1);
                    sellOrder.setUserId(studentPaymentOrder.getUserId());
                    sellOrder.setPaymentChannel(studentPaymentOrder.getPaymentChannel());
                    sellOrder.setMerNo(studentPaymentOrder.getMerNos());
                    sellOrder.setSellTime(studentPaymentOrder.getCreateTime());
                    sellOrder.setCreateIme(new Date());
                    sellOrder.setUpdateTime(new Date());
                    if (goods.getType().equals(GoodsType.INSTRUMENT)) {
                        sellOrder.setType(SellTypeEnum.INSTRUMENT);
                    } else if (goods.getType().equals(GoodsType.ACCESSORIES)) {
                        sellOrder.setType(SellTypeEnum.ACCESSORIES);
                    } else {
                        sellOrder.setType(SellTypeEnum.OTHER);
                    }
                    //租赁、免费的没有销售收入，有销售成本
                    if (orderDetail.getType().equals(OrderDetailTypeEnum.MUSICAL) &&
                            (orderDetail.getKitGroupPurchaseType().equals(KitGroupPurchaseTypeEnum.LEASE) ||
                                    orderDetail.getKitGroupPurchaseType().equals(KitGroupPurchaseTypeEnum.FREE)
                            )) {
                        sellOrder.setActualAmount(BigDecimal.ZERO);
                        sellOrder.setBalanceAmount(BigDecimal.ZERO);
                        sellOrder.setExpectAmount(BigDecimal.ZERO);
                    }
                    sellOrder.setHasRoute(true);
                    if (complementGoodsNum <= 0) {
                        break;
                    }
                }

            }
            sellOrders.addAll(sellOrderList);
        }
        if (sellOrders.size() > 0) {
            sellOrderDao.batchInsert(sellOrders);
        }
        return sellOrders;
    }

    @Override
    public void batchInsert(List<SellOrder> sellOrders) {
        sellOrderDao.batchInsert(sellOrders);
    }

    @Override
    public List<SellOrder> getSellOrderByParentGoodsId(Long orderId, Integer parentGoodsId) {
        return sellOrderDao.getSellOrderByParentGoodsId(orderId, parentGoodsId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class, isolation = Isolation.READ_COMMITTED)
    public List<SellOrder> refund(List<SellOrder> sellOrders, Boolean reBackFee) {
        Date nowDate = new Date();
        for (SellOrder sellOrder : sellOrders) {
            //1、更改销售列表状态
            sellOrder.setStatus(SellStatus.REFUND);
            sellOrder.setUpdateTime(nowDate);
            sellOrder.setRefundTime(nowDate);
            sellOrderDao.update(sellOrder);

            //2、金额退到余额
            if (reBackFee && sellOrder.getExpectAmount().compareTo(BigDecimal.ZERO) > 0) {
                sysUserCashAccountService.updateBalance(sellOrder.getUserId(), sellOrder.getExpectAmount(), PlatformCashAccountDetailTypeEnum.REFUNDS, "订单：" + sellOrder.getOrderId() + " 商品id：" + sellOrder.getGoodsId() + "退货");
            }
        }
        //3、退货
        if (sellOrders.get(0).getAccountType() != null) {
            goodsService.increaseStock(sellOrders, sellOrders.get(0).getAccountType());
        }
        return sellOrders;
    }

    @Override
    public List<SellOrder> refundByOrderId(Long orderId, Boolean reBackFee) {
        List<SellOrder> sellOrders = sellOrderDao.getSellOrderByParentGoodsId(orderId, null);
        if (sellOrders.size() <= 0) {
            return sellOrders;
        }
        return refund(sellOrders, reBackFee);
    }

    @Override
    public List<SellOrder> getRefundSellOrder(Long orderId) {
        return sellOrderDao.getRefundSellOrder(orderId);
    }

    @Override
    public Map<String, BigDecimal> getSellAmount(String orderNo) {
        StudentPaymentOrder order = studentPaymentOrderDao.findOrderByOrderNo(orderNo);
        if (order == null) {
            return null;
        }

        //零星支付除了充值其他都是服务费用
        if (order.getType().equals(OrderTypeEnum.SPORADIC)) {
            SporadicChargeInfo info = sporadicChargeInfoDao.get(Integer.parseInt(order.getMusicGroupId()));
            if (info.getChargeType().equals(SporadicChargeTypeEnum.RECHARGE)) {
                return null;
            }
        }
        Map<String, BigDecimal> sellAmount = new HashMap<>();
        //乐器销售,声部更改
        if (order.getType().equals(OrderTypeEnum.GOODS_SELL) || order.getType().equals(OrderTypeEnum.SUBJECT_CHANGE)) {
            sellAmount.put("actualAmount", order.getActualAmount());
            sellAmount.put("balance", order.getBalancePaymentAmount() == null ? BigDecimal.ZERO : order.getBalancePaymentAmount());
            return sellAmount;
        }

        //乐器维修
        if (order.getType().equals(OrderTypeEnum.REPAIR)) {
            StudentRepair repairInfo = studentRepairDao.getRepairInfo(Integer.parseInt(order.getMusicGroupId()));

            if (StringUtils.isBlank(repairInfo.getGoodsJson())) {
                sellAmount.put("actualAmount", BigDecimal.ZERO);
                sellAmount.put("balance", BigDecimal.ZERO);
                return sellAmount;
            }
            List<Goods> goodies = JSONObject.parseArray(repairInfo.getGoodsJson(), Goods.class);
            List<Integer> goodsIds = goodies.stream().map(Goods::getId).collect(Collectors.toList());
            if (goodsIds.size() <= 0) {
                sellAmount.put("actualAmount", BigDecimal.ZERO);
                sellAmount.put("balance", BigDecimal.ZERO);
                return sellAmount;
            }

            BigDecimal goodsTotalPrice = BigDecimal.ZERO;
            goodies = goodsDao.getGoodies(goodsIds);
            int i = 1;
            for (Integer goodsId : goodsIds) {
                for (Goods goods : goodies) {
                    if (goods.getId().equals(goodsId)) {
                        goodsTotalPrice = goodsTotalPrice.add(goods.getDiscountPrice());
                        break;
                    }
                }
            }
            BigDecimal balance = order.getBalancePaymentAmount() == null ? BigDecimal.ZERO : order.getBalancePaymentAmount();
            BigDecimal goodsTotalBalance = goodsTotalPrice.multiply(balance).divide(order.getExpectAmount(), 2, BigDecimal.ROUND_HALF_UP);
            sellAmount.put("actualAmount", goodsTotalPrice.subtract(goodsTotalBalance));
            sellAmount.put("balance", goodsTotalBalance);
            return sellAmount;
        }

        //乐团报名
        if (order.getType().equals(OrderTypeEnum.APPLY)) {
            List<StudentPaymentOrderDetail> orderDetails = studentPaymentOrderDetailDao.getOrderDetail(order.getId());
            //总余额支付
            BigDecimal totalBalance = order.getBalancePaymentAmount() != null ? order.getBalancePaymentAmount() : BigDecimal.ZERO;
            //总价格
            BigDecimal totalPrice = order.getExpectAmount();
            //商品总付款
            BigDecimal detailTotalPrice = orderDetails.stream().map(StudentPaymentOrderDetail::getPrice).reduce(BigDecimal.ZERO, BigDecimal::add);
            //商品销售占的余额
            BigDecimal detailTotalBalance = detailTotalPrice.multiply(totalBalance).divide(totalPrice, 2, BigDecimal.ROUND_HALF_UP);

            sellAmount.put("actualAmount", detailTotalPrice.subtract(detailTotalBalance));
            sellAmount.put("balance", detailTotalBalance);
            return sellAmount;
        }

        sellAmount.put("actualAmount", BigDecimal.ZERO);
        sellAmount.put("balance", BigDecimal.ZERO);
        return sellAmount;
    }

}
