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

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.dal.page.SubjectChangeQueryInfo;
import com.ym.mec.biz.service.*;
import com.ym.mec.common.dal.BaseDAO;
import com.ym.mec.common.exception.BizException;
import com.ym.mec.common.page.PageInfo;
import com.ym.mec.common.service.IdGeneratorService;
import com.ym.mec.common.service.impl.BaseServiceImpl;
import com.ym.mec.thirdparty.message.MessageSenderPluginContext;
import com.ym.mec.util.collection.MapUtil;
import com.ym.mec.util.date.DateUtil;
import org.apache.commons.lang3.StringUtils;
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.Isolation;
import org.springframework.transaction.annotation.Transactional;

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

@Service
public class SubjectChangeServiceImpl extends BaseServiceImpl<Integer, SubjectChange> implements SubjectChangeService {

    @Autowired
    private SubjectChangeDao subjectChangeDao;
    @Autowired
    private GoodsDao goodsDao;
    @Autowired
    private StudentDao studentDao;
    @Autowired
    private IdGeneratorService idGeneratorService;
    @Autowired
    private StudentPaymentOrderService studentPaymentOrderService;
    @Autowired
    private SysUserCashAccountService sysUserCashAccountService;
    @Autowired
    private StudentPaymentRouteOrderService studentPaymentRouteOrderService;
    @Autowired
    private SysConfigDao sysConfigDao;
    @Autowired
    private PayService payService;
    @Autowired
    private StudentPaymentOrderDetailDao studentPaymentOrderDetailDao;
    @Autowired
    private MusicGroupDao musicGroupDao;
    @Autowired
    private SellOrderDao sellOrderDao;
    @Autowired
    private SysUserCashAccountDetailService sysUserCashAccountDetailService;
    @Autowired
    private SysMessageService sysMessageService;
    @Autowired
    private StudentRegistrationService studentRegistrationService;
    @Autowired
    private ContractService contractService;
    @Autowired
    private SysPaymentConfigService sysPaymentConfigService;
    @Autowired
    private StudentPaymentOrderDao studentPaymentOrderDao;
    @Autowired
    private SellOrderService sellOrderService;
    @Autowired
    private GoodsService goodsService;

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

    @Override
    public BaseDAO<Integer, SubjectChange> getDAO() {
        return subjectChangeDao;
    }

    @Override
    public SubjectChange getChangeInfo(Integer id) {
        SubjectChange subjectChange = subjectChangeDao.getChangeInfo(id);
        if (subjectChange == null) {
            return null;
        }
        if (subjectChange.getOriginalMusical() != null) {
            subjectChange.setOriginalMusicalGoods(goodsDao.get(subjectChange.getOriginalMusical()));
        }
        if (subjectChange.getOriginalAccessories() != null) {
            subjectChange.setOriginalAccessoriesGoods(goodsDao.findGoodsByIds(subjectChange.getOriginalAccessories()));
        }

        if (subjectChange.getChangeMusical() != null) {
            subjectChange.setChangeMusicalGoods(goodsDao.get(subjectChange.getChangeMusical()));
        }
        if (subjectChange.getChangeAccessories() != null) {
            subjectChange.setChangeAccessoriesGoods(goodsDao.findGoodsByIds(subjectChange.getChangeAccessories()));
        }

        return subjectChange;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map payChange(Integer id, BigDecimal viewAmount, Boolean isUseBalancePayment, Boolean isRepay) throws Exception {
        Date date = new Date();
        SubjectChange subjectChange = subjectChangeDao.get(id);
        if (isRepay) {
            StudentPaymentOrder studentPaymentOrder = studentPaymentOrderService.get(subjectChange.getOrderId().longValue());
            studentPaymentOrder.setStatus(DealStatusEnum.CLOSE);
            studentPaymentOrder.setUpdateTime(date);
            studentPaymentOrderService.update(studentPaymentOrder);
            subjectChange.setStatus(SubjectChangeStatusEnum.WAIT_PAY);
        }

        if (subjectChange.getStatus().equals(SubjectChangeStatusEnum.CANCELED)) {
            throw new BizException("声部更改已取消,请勿缴费");
        }
        if (subjectChange.getStatus().equals(SubjectChangeStatusEnum.SUCCESSED)) {
            throw new BizException("声部更改已缴费,请勿重复缴费");
        }

        MusicGroup musicGroup = musicGroupDao.get(subjectChange.getMusicGroupId());
        if (!musicGroup.getStatus().equals(MusicGroupStatusEnum.APPLY) && !musicGroup.getStatus().equals(MusicGroupStatusEnum.PAY)) {
            throw new BizException("乐团当前状态不能缴声部更改费用");
        }
        BigDecimal amount = subjectChange.getGoodsMargin().add(subjectChange.getCourseMargin());

        studentDao.lockUser(subjectChange.getStudentId());

        String orderNo = idGeneratorService.generatorId("payment") + "";

        String channelType = "";

        StudentPaymentOrder studentPaymentOrder = new StudentPaymentOrder();
        studentPaymentOrder.setUserId(subjectChange.getStudentId());
        studentPaymentOrder.setGroupType(GroupType.SUBJECT_CHANGE);
        studentPaymentOrder.setOrderNo(orderNo);
        studentPaymentOrder.setType(OrderTypeEnum.SUBJECT_CHANGE);
        studentPaymentOrder.setExpectAmount(amount);
        studentPaymentOrder.setActualAmount(amount);
        studentPaymentOrder.setStatus(DealStatusEnum.ING);
        studentPaymentOrder.setMusicGroupId(subjectChange.getId().toString());
        studentPaymentOrder.setPaymentChannel("BALANCE");
        studentPaymentOrder.setUpdateTime(date);
        studentPaymentOrder.setOrganId(subjectChange.getOrganId());
        studentPaymentOrder.setRoutingOrganId(subjectChange.getOrganId());

        studentPaymentOrderService.insert(studentPaymentOrder);

        subjectChange.setOrderId(studentPaymentOrder.getId().intValue());
        subjectChange.setOrderNo(orderNo);
        subjectChange.setOrganId(studentPaymentOrder.getOrganId());
        subjectChange.setUpdateTime(date);
        subjectChange.setStatus(SubjectChangeStatusEnum.ING);
        if (subjectChangeDao.update(subjectChange) <= 0) {
            throw new BizException("下单失败，请重试");
        }

        studentPaymentOrder.setVersion(0);
        if (amount.compareTo(viewAmount) != 0) {
            throw new BizException("价格异常");
        }

        BigDecimal balance = BigDecimal.ZERO;
        if (isUseBalancePayment != null && isUseBalancePayment && amount.compareTo(BigDecimal.ZERO) > 0) {
            SysUserCashAccount userCashAccount = sysUserCashAccountService.getLocked(subjectChange.getStudentId());
            if (userCashAccount == null) {
                throw new BizException("用户账户找不到");
            }
            if (userCashAccount.getBalance() != null && userCashAccount.getBalance().compareTo(BigDecimal.ZERO) > 0) {
                balance = amount.compareTo(userCashAccount.getBalance()) >= 0 ? userCashAccount.getBalance() : amount;
                amount = amount.subtract(balance);
                studentPaymentOrder.setActualAmount(amount);
                studentPaymentOrder.setBalancePaymentAmount(balance);
                sysUserCashAccountService.updateBalance(subjectChange.getStudentId(), balance.negate(), PlatformCashAccountDetailTypeEnum.PAY_FEE, "乐器维修");
            }
        }
        if (amount.compareTo(viewAmount) != 0) {
            throw new BizException("价格异常");
        }
        studentPaymentOrderService.update(studentPaymentOrder);

        studentPaymentOrder.setVersion(studentPaymentOrder.getVersion() + 1);

        if (amount.compareTo(BigDecimal.ZERO) == 0) {
            studentPaymentRouteOrderService.addRouteOrder(orderNo, subjectChange.getOrganId(), studentPaymentOrder.getExpectAmount());
            Map<String, String> notifyMap = new HashMap<>();
            notifyMap.put("tradeState", "1");
            notifyMap.put("merOrderNo", studentPaymentOrder.getOrderNo());
            notifyMap.put("channelType", channelType);
            notifyMap.put("orderNo", "");
            studentPaymentOrderService.updateOrder(notifyMap);
            notifyMap.put("orderNo", orderNo);
            return notifyMap;
        }

        String baseApiUrl = sysConfigDao.findConfigValue(SysConfigService.BASE_API_URL);

        Map<String, Object> payMap = payService.getPayMap(
                amount,
                balance,
                orderNo,
                baseApiUrl + "/api-student/studentOrder/notify",
                baseApiUrl + "/api-student/studentOrder/paymentResult?orderNo=" + orderNo,
                "声部更换",
                "声部更换",
                subjectChange.getOrganId(),
                "subjectChange"
        );

        studentPaymentOrder.setMerNos((String) payMap.get("routingMerNos"));
        studentPaymentOrder.setPaymentChannel((String) payMap.get("type"));
        studentPaymentOrder.setUpdateTime(date);
        studentPaymentOrderService.update(studentPaymentOrder);
        return payMap;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public SubjectChange addChange(SubjectChange subjectChange) {
        SubjectChange studentWaitPay = subjectChangeDao.getStudentWaitPay(subjectChange.getStudentId(), subjectChange.getMusicGroupId());
        if (studentWaitPay != null) {
            throw new BizException("已有未支付的声部更改，请勿重复创建");
        }
        Date nowDate = new Date();
        SubjectChange studentOriginal = getStudentOriginal(subjectChange.getStudentId(), subjectChange.getMusicGroupId());
        subjectChange.setOriginalOrderId(studentOriginal.getOrderId());
        subjectChange.setOriginalCost(studentOriginal.getOriginalCost());
        subjectChange.setStatus(SubjectChangeStatusEnum.WAIT_PAY);
        MusicGroup musicGroup = musicGroupDao.get(subjectChange.getMusicGroupId());
        subjectChange.setOrganId(musicGroup.getOrganId());
        subjectChange.setEduTeacherId(musicGroup.getEducationalTeacherId());
        subjectChange.setCourseMargin(subjectChange.getChangeCourseFee().subtract(subjectChange.getOriginalCourseFee()));
        BigDecimal goodsMargin = subjectChange.getChangeMusicalPrice().add(subjectChange.getChangeAccessoriesPrice())
                .subtract(subjectChange.getOriginalMusicalPrice()).subtract(subjectChange.getOriginalAccessoriesPrice());
        subjectChange.setGoodsMargin(goodsMargin);
        subjectChange.setOriginalKitGroupPurchaseType(
                studentOriginal.getOriginalKitGroupPurchaseType() == null ? KitGroupPurchaseTypeEnum.OWNED : studentOriginal.getOriginalKitGroupPurchaseType());
        String goodsIds = "";
        if (subjectChange.getKitGroupPurchaseType().equals(KitGroupPurchaseTypeEnum.OWNED)) {
            subjectChange.setChangeMusical(null);
        }
        if (subjectChange.getChangeMusical() != null) {
            goodsIds += subjectChange.getChangeMusical() + "";
        }
        if (subjectChange.getChangeAccessories() != null) {
            goodsIds += StringUtils.isNotBlank(goodsIds) ? "," + subjectChange.getChangeAccessories() : subjectChange.getChangeAccessories();
        }
        BigDecimal goodsPrice = BigDecimal.ZERO;
        List<Goods> goodies = goodsDao.findGoodsByIds(goodsIds);
        for (Goods goods : goodies) {
            goodsPrice = goodsPrice.add(goods.getDiscountPrice());
        }
        subjectChange.setChangeCost(goodsPrice);
        subjectChange.setCostMargin(subjectChange.getChangeCost().subtract(subjectChange.getOriginalCost()));
        //差价 <= 0
        BigDecimal amountMargin = subjectChange.getGoodsMargin().add(subjectChange.getCourseMargin());
        if (amountMargin.compareTo(BigDecimal.ZERO) <= 0) {
            subjectChange.setStatus(SubjectChangeStatusEnum.SUCCESSED);
            subjectChange.setSellAmount(BigDecimal.ZERO);
            subjectChange.setSellTime(nowDate);
        }
        //差价小于0退到余额
        if (amountMargin.compareTo(BigDecimal.ZERO) <= 0) {
            sysUserCashAccountService.updateBalance(subjectChange.getStudentId(), amountMargin.negate(), PlatformCashAccountDetailTypeEnum.REFUNDS, "声部更换退还");
            studentRegistrationService.changeStudentSubject(subjectChange.getStudentId(), subjectChange.getMusicGroupId(), subjectChange.getOriginalSubjectId(), subjectChange.getChangeSubjectId());
        }
        subjectChange.setCreateTime(nowDate);
        subjectChange.setUpdateTime(nowDate);
        subjectChange.setVersion(0);
        subjectChangeDao.insert(subjectChange);

        if (amountMargin.compareTo(BigDecimal.ZERO) <= 0) {
            String orderNo = idGeneratorService.generatorId("payment") + "";
            StudentPaymentOrder studentPaymentOrder = new StudentPaymentOrder();
            studentPaymentOrder.setUserId(subjectChange.getStudentId());
            studentPaymentOrder.setGroupType(GroupType.SUBJECT_CHANGE);
            studentPaymentOrder.setOrderNo(orderNo);
            studentPaymentOrder.setType(OrderTypeEnum.SUBJECT_CHANGE);
            studentPaymentOrder.setExpectAmount(BigDecimal.ZERO);
            studentPaymentOrder.setActualAmount(BigDecimal.ZERO);
            studentPaymentOrder.setBalancePaymentAmount(BigDecimal.ZERO);
            studentPaymentOrder.setStatus(DealStatusEnum.SUCCESS);
            studentPaymentOrder.setMusicGroupId(subjectChange.getId().toString());
            studentPaymentOrder.setPaymentChannel("BALANCE");
            studentPaymentOrder.setUpdateTime(nowDate);
            studentPaymentOrder.setOrganId(subjectChange.getOrganId());
            studentPaymentOrder.setRoutingOrganId(subjectChange.getOrganId());
            studentPaymentOrderService.insert(studentPaymentOrder);

            subjectChange.setOrderId(studentPaymentOrder.getId().intValue());
            subjectChange.setOrderNo(orderNo);
            subjectChangeDao.update(subjectChange);

            //退原订单商品
            sellOrderService.refundByOrderId(subjectChange.getOriginalOrderId().longValue(), false);

            if (StringUtils.isNotBlank(goodsIds)) {
                List<Integer> goodsIdList = Arrays.stream(goodsIds.split(",")).map(Integer::parseInt).collect(Collectors.toList());
                //添加新订单
                this.addSellOrder(studentPaymentOrder.getId(), subjectChange.getMusicGroupId(), goodsIdList, BigDecimal.ZERO, BigDecimal.ZERO, subjectChange.getKitGroupPurchaseType());
            }
        }
        return subjectChange;
    }

    @Override
    public SubjectChange cancel(Integer id) {
        SubjectChange subjectChange = subjectChangeDao.get(id);
        if (!subjectChange.getStatus().equals(SubjectChangeStatusEnum.WAIT_PAY)) {
            throw new BizException("不是待支付状态，不能取消");
        }
        subjectChange.setStatus(SubjectChangeStatusEnum.CANCELED);
        subjectChange.setUpdateTime(new Date());
        if (subjectChangeDao.update(subjectChange) <= 0) {
            throw new BizException("取消失败,请重试");
        }
        return subjectChange;
    }

    @Override
    public SubjectChange getStudentOriginal(Integer studentId, String musicGroupId) {
        //1、存在历史的更换
        SubjectChange subjectChange = new SubjectChange();
        SubjectChange studentLastChange = subjectChangeDao.getStudentLastChange(studentId, musicGroupId);
        if (studentLastChange != null) {
            Set<Integer> refundSellOrderGoodsIds = getRefundGoodsId(studentLastChange.getOrderId().longValue());
            subjectChange.setStudentId(studentLastChange.getStudentId());
            subjectChange.setOrderId(studentLastChange.getOrderId());
            subjectChange.setCooperationOrganId(studentLastChange.getCooperationOrganId());
            subjectChange.setMusicGroupId(studentLastChange.getMusicGroupId());
            subjectChange.setOriginalCourseFee(studentLastChange.getChangeCourseFee());
            subjectChange.setKitGroupPurchaseType(studentLastChange.getKitGroupPurchaseType());

            BigDecimal originalCost = BigDecimal.ZERO;
            if (studentLastChange.getChangeMusical() != null && !refundSellOrderGoodsIds.contains(studentLastChange.getChangeMusical())) {
                subjectChange.setOriginalMusical(studentLastChange.getChangeMusical());
                subjectChange.setOriginalMusicalGoods(goodsDao.get(studentLastChange.getChangeMusical()));
                subjectChange.setOriginalMusicalPrice(studentLastChange.getChangeMusicalPrice());
            }

            if (studentLastChange.getChangeAccessories() != null) {
                String[] goodsIdArr = studentLastChange.getChangeAccessories().split(",");
                String accessoriesId = "";
                for (String goodsId : goodsIdArr) {
                    if (refundSellOrderGoodsIds.contains(Integer.parseInt(goodsId))) {
                        continue;
                    }
                    accessoriesId += StringUtils.isBlank(accessoriesId) ? goodsId : "," + goodsId;
                }
                if (StringUtils.isNotBlank(accessoriesId)) {
                    subjectChange.setOriginalAccessories(accessoriesId);
                    List<Goods> accessoriesGoods = goodsDao.findGoodsByIds(accessoriesId);
                    subjectChange.setOriginalAccessoriesGoods(accessoriesGoods);
                    BigDecimal price = accessoriesGoods.stream().map(Goods::getGroupPurchasePrice).reduce(BigDecimal.ZERO, BigDecimal::add);
                    subjectChange.setOriginalAccessoriesPrice(price);
                }
            }
            subjectChange.setOriginalCost(originalCost);
            return subjectChange;
        }
        //2.1不存在历史的更换
        List<StudentPaymentOrderDetail> details = studentPaymentOrderDetailDao.getStudentApplyDetail(studentId, musicGroupId);
        if (details.size() <= 0) {
            return null;
        }

        Set<Integer> refundSellOrderGoodsIds = getRefundGoodsId(details.get(0).getPaymentOrderId());

        MusicGroup musicGroup = musicGroupDao.get(musicGroupId);
        subjectChange.setStudentId(studentId);
        subjectChange.setOrganId(musicGroup.getOrganId());
        subjectChange.setCooperationOrganId(musicGroup.getCooperationOrganId());
        subjectChange.setMusicGroupId(musicGroupId);
        subjectChange.setOrderId(details.get(0).getPaymentOrderId().intValue());
        String accessoriesIds = "";
        BigDecimal accessoriesPrice = BigDecimal.ZERO;
        for (StudentPaymentOrderDetail detail : details) {
            if (detail.getType().equals(OrderDetailTypeEnum.COURSE)) {
                subjectChange.setOriginalCourseFee(detail.getPrice());
            } else if (detail.getType().equals(OrderDetailTypeEnum.MUSICAL)) {
                subjectChange.setOriginalKitGroupPurchaseType(detail.getKitGroupPurchaseType());
                Integer goodsId = Integer.parseInt(detail.getGoodsIdList());
                if (!refundSellOrderGoodsIds.contains(goodsId)) {
                    subjectChange.setOriginalMusical(goodsId);
                    subjectChange.setOriginalMusicalGoods(goodsDao.get(goodsId));
                    subjectChange.setOriginalMusicalPrice(detail.getPrice());
                }
            } else {
                if (StringUtils.isNotBlank(detail.getGoodsIdList())) {
                    accessoriesPrice = accessoriesPrice.add(detail.getPrice());
                    accessoriesIds = accessoriesIds.length() > 0 ? accessoriesIds + "," + detail.getGoodsIdList() : detail.getGoodsIdList();
                }
            }
        }
        if (StringUtils.isNotBlank(accessoriesIds)) {
            String[] goodsIdArr = accessoriesIds.split(",");
            String accessoriesId = "";
            for (String goodsId : goodsIdArr) {
                if (refundSellOrderGoodsIds.contains(Integer.parseInt(goodsId))) {
                    continue;
                }
                accessoriesId += StringUtils.isBlank(accessoriesId) ? goodsId : "," + goodsId;
            }

            subjectChange.setOriginalAccessories(accessoriesId);
            List<Goods> accessoriesGoods = goodsDao.findGoodsByIds(accessoriesId);
            subjectChange.setOriginalAccessoriesGoods(accessoriesGoods);
            BigDecimal price = accessoriesGoods.stream().map(Goods::getGroupPurchasePrice).reduce(BigDecimal.ZERO, BigDecimal::add);
            subjectChange.setOriginalAccessoriesPrice(price);
        }
        Long orderId = details.get(0).getPaymentOrderId();
        //2.2 计算销售成本
        BigDecimal orderSellCost = sellOrderDao.getOrderSellCost(orderId);
        subjectChange.setOriginalCost(orderSellCost == null ? BigDecimal.ZERO : orderSellCost);
        return subjectChange;
    }

    private Set<Integer> getRefundGoodsId(Long orderId) {
        List<SellOrder> refundSellOrders = sellOrderService.getRefundSellOrder(orderId);
        Set<Integer> refundSellOrderGoodsIds = refundSellOrders.stream().filter(e -> e.getParentGoodsId() == null).map(SellOrder::getGoodsId).collect(Collectors.toSet());
        Set<Integer> refundSellOrderParentGoodsId = refundSellOrders.stream().filter(e -> e.getParentGoodsId() != null).map(SellOrder::getParentGoodsId).collect(Collectors.toSet());
        refundSellOrderGoodsIds.addAll(refundSellOrderParentGoodsId);
        return refundSellOrderGoodsIds;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean orderCallback(StudentPaymentOrder studentPaymentOrder) {
        Date nowDate = new Date();
        //更新订单信息
        studentPaymentOrder.setUpdateTime(nowDate);
        int updateCount = studentPaymentOrderService.update(studentPaymentOrder);
        if (updateCount <= 0) {
            throw new BizException("订单更新失败");
        }

        //更新声部更改信息状态
        SubjectChange subjectChange = subjectChangeDao.get(Integer.parseInt(studentPaymentOrder.getMusicGroupId()));
        if (subjectChange == null) {
            throw new BizException("声部更换订单不存在");
        }
        if (!subjectChange.getStatus().equals(SubjectChangeStatusEnum.ING)) {
            return true;
        }

        subjectChange.setUpdateTime(nowDate);
        subjectChange.setTransNo(studentPaymentOrder.getTransNo());
        subjectChange.setMerNo(studentPaymentOrder.getMerNos());
        subjectChange.setPaymentChannel(studentPaymentOrder.getPaymentChannel());

        Integer userId = studentPaymentOrder.getUserId();

        Map<Integer, String> map = new HashMap<>();
        map.put(userId, userId.toString());

        if (studentPaymentOrder.getStatus() == DealStatusEnum.SUCCESS) {
            try {
                contractService.transferProduceContract(userId, null);
            } catch (Exception e) {
                logger.error("产品协议生成失败", e);
            }
            //更新声部信息报名数量
            studentRegistrationService.changeStudentSubject(subjectChange.getStudentId(), subjectChange.getMusicGroupId(), subjectChange.getOriginalSubjectId(), subjectChange.getChangeSubjectId());

            subjectChange.setStatus(SubjectChangeStatusEnum.SUCCESSED);
            subjectChange.setSellTime(nowDate);

            //乐器辅件价差大于0时，有销售金额
            if (subjectChange.getKitGroupPurchaseType().equals(KitGroupPurchaseTypeEnum.GROUP) && studentPaymentOrder.getActualAmount().compareTo(BigDecimal.ZERO) > 0) {
                BigDecimal sellAmount = studentPaymentOrder.getActualAmount().multiply(subjectChange.getGoodsMargin())
                        .divide(studentPaymentOrder.getExpectAmount(), 2, BigDecimal.ROUND_HALF_UP);
                subjectChange.setSellAmount(sellAmount);
            }

            if (this.update(subjectChange) <= 0) {
                throw new BizException("维修单更新失败");
            }
            String goodsIds = "";
            if (subjectChange.getChangeMusical() != null) {
                goodsIds += subjectChange.getChangeMusical() + "";
            }
            if (subjectChange.getChangeAccessories() != null) {
                goodsIds += StringUtils.isNotBlank(goodsIds) ? "," + subjectChange.getChangeAccessories() : subjectChange.getChangeAccessories();
            }
            if (StringUtils.isNotBlank(goodsIds)) {
                List<Integer> goodsIdList = Arrays.stream(goodsIds.split(",")).map(Integer::parseInt).collect(Collectors.toList());
                //退原订单商品
                sellOrderService.refundByOrderId(subjectChange.getOriginalOrderId().longValue(), false);
                //添加新订单
                this.addSellOrder(studentPaymentOrder.getId(), subjectChange.getMusicGroupId(), goodsIdList, studentPaymentOrder.getExpectAmount(), studentPaymentOrder.getBalancePaymentAmount(), subjectChange.getKitGroupPurchaseType());
            }

            //插入交易明细
            BigDecimal amount = studentPaymentOrder.getActualAmount();
            SysUserCashAccount cashAccount = sysUserCashAccountService.get(userId);
            //充值
            SysUserCashAccountDetail rechargeDetail = new SysUserCashAccountDetail();
            rechargeDetail.setAmount(amount);
            rechargeDetail.setBalance(cashAccount.getBalance().add(amount));
            rechargeDetail.setComment("缴费前充值");
            rechargeDetail.setCreateTime(nowDate);
            rechargeDetail.setStatus(DealStatusEnum.SUCCESS);
            rechargeDetail.setTransNo(studentPaymentOrder.getTransNo());
            rechargeDetail.setType(PlatformCashAccountDetailTypeEnum.RECHARGE);
            rechargeDetail.setUpdateTime(nowDate);
            rechargeDetail.setUserId(userId);
            rechargeDetail.setChannel(studentPaymentOrder.getPaymentChannel());
            rechargeDetail.setComAmount(studentPaymentOrder.getComAmount());
            rechargeDetail.setPerAmount(studentPaymentOrder.getPerAmount());
            sysUserCashAccountDetailService.insert(rechargeDetail);

            //缴费
            SysUserCashAccountDetail paymentDetail = new SysUserCashAccountDetail();
            paymentDetail.setAmount(amount.negate());
            paymentDetail.setBalance(cashAccount.getBalance());
            paymentDetail.setComment("声部更改");
            paymentDetail.setCreateTime(nowDate);
            paymentDetail.setStatus(DealStatusEnum.SUCCESS);
            paymentDetail.setTransNo(studentPaymentOrder.getTransNo());
            paymentDetail.setType(PlatformCashAccountDetailTypeEnum.PAY_FEE);
            paymentDetail.setUpdateTime(nowDate);
            paymentDetail.setUserId(userId);
            rechargeDetail.setChannel(studentPaymentOrder.getPaymentChannel());
            if (studentPaymentOrder.getComAmount() != null) {
                rechargeDetail.setComAmount(studentPaymentOrder.getComAmount().negate());
                rechargeDetail.setPerAmount(studentPaymentOrder.getPerAmount().negate());
            }
            sysUserCashAccountDetailService.insert(paymentDetail);
        }

        if (studentPaymentOrder.getStatus() == DealStatusEnum.CLOSE || studentPaymentOrder.getStatus() == DealStatusEnum.FAILED) {
            subjectChange.setStatus(SubjectChangeStatusEnum.WAIT_PAY);
            if (this.update(subjectChange) <= 0) {
                throw new BizException("声部更改订单更新失败");
            }
            if (studentPaymentOrder.getBalancePaymentAmount() != null && studentPaymentOrder.getBalancePaymentAmount().compareTo(BigDecimal.ZERO) > 0) {
                sysUserCashAccountService.updateBalance(studentPaymentOrder.getUserId(), studentPaymentOrder.getBalancePaymentAmount(), PlatformCashAccountDetailTypeEnum.REFUNDS, "声部更改支付失败");
            }

            sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.JIGUANG, MessageTypeEnum.SMS_SPORADIC_PAYMENT_FAILED, map, null, 0, "", "STUDENT",
                    studentPaymentOrder.getActualAmount(), "声部更换");
            return false;
        }
        return true;
    }

    @Override
    public PageInfo<SubjectChange> getPageList(SubjectChangeQueryInfo queryInfo) {
        if (queryInfo.getEndTime() != null) {
            queryInfo.setEndTime(DateUtil.getLastTimeWithDay(queryInfo.getEndTime()));
        }
        PageInfo<SubjectChange> pageInfo = new PageInfo<>(queryInfo.getPage(), queryInfo.getRows());
        Map<String, Object> params = new HashMap<String, Object>();
        MapUtil.populateMap(params, queryInfo);

        List<SubjectChange> dataList = new ArrayList<>();
        int count = subjectChangeDao.queryCount(params);

        if (count > 0) {
            pageInfo.setTotal(count);
            params.put("offset", pageInfo.getOffset());
            dataList = subjectChangeDao.getPageList(params);
            for (SubjectChange subjectChange : dataList) {
                if (subjectChange.getOriginalMusical() != null) {
                    subjectChange.setOriginalMusicalGoods(goodsDao.get(subjectChange.getOriginalMusical()));
                }
                if (subjectChange.getOriginalAccessories() != null) {
                    subjectChange.setOriginalAccessoriesGoods(goodsDao.findGoodsByIds(subjectChange.getOriginalAccessories()));
                }
                if (subjectChange.getChangeMusical() != null) {
                    subjectChange.setChangeMusicalGoods(goodsDao.get(subjectChange.getChangeMusical()));
                }
                if (subjectChange.getChangeAccessories() != null) {
                    subjectChange.setChangeAccessoriesGoods(goodsDao.findGoodsByIds(subjectChange.getChangeAccessories()));
                }
            }
        }
        pageInfo.setRows(dataList);
        return pageInfo;
    }

    @Override
    public SubjectChange updateCostMargin(Integer id, BigDecimal costMargin) {
        SubjectChange subjectChange = subjectChangeDao.get(id);
        subjectChange.setCostMargin(costMargin);
        subjectChange.setUpdateTime(new Date());
        if (subjectChangeDao.update(subjectChange) <= 0) {
            throw new BizException("更新成本差失败,请重试");
        }
        return subjectChange;
    }

    @Override
    @Transactional(rollbackFor = Exception.class, isolation = Isolation.READ_COMMITTED)
    public List<SellOrder> addSellOrder(Long orderId, String musicGroupId, List<Integer> goodsIds, BigDecimal totalAmount, BigDecimal balance, KitGroupPurchaseTypeEnum kitGroupPurchaseType) {
        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.getGroupPurchasePrice());
                    break;
                }
            }
        }

        BigDecimal hasRouteBalance = BigDecimal.ZERO;
        BigDecimal hasRouteExpectAmount = BigDecimal.ZERO;

        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.getGroupPurchasePrice();
            BigDecimal expectAmount = BigDecimal.ZERO;
            BigDecimal goodsBalance = BigDecimal.ZERO;

            if (goodsTotalPrice.compareTo(BigDecimal.ZERO) > 0) {
                goodsBalance = balance.multiply(goodsPrice).divide(goodsTotalPrice, 2, BigDecimal.ROUND_DOWN);
                expectAmount = totalAmount.multiply(goodsPrice).divide(goodsTotalPrice, 2, BigDecimal.ROUND_DOWN);
            }
            if (i == goodsNum) {
                goodsBalance = balance.subtract(hasRouteBalance);
                expectAmount = totalAmount.subtract(hasRouteExpectAmount);
            }
            //租赁、免费的没有销售收入，有销售成本
            if (nowGoods.getType().equals(GoodsType.INSTRUMENT) && (kitGroupPurchaseType.equals(KitGroupPurchaseTypeEnum.LEASE) || kitGroupPurchaseType.equals(KitGroupPurchaseTypeEnum.FREE))) {
                goodsBalance = BigDecimal.ZERO;
                expectAmount = BigDecimal.ZERO;
            }

            hasRouteBalance = hasRouteBalance.add(goodsBalance);
            hasRouteExpectAmount = hasRouteExpectAmount.add(expectAmount);
            i++;

            int complementGoodsNum = nowGoods.getComplementGoodsIdList() == null ? 1 : nowGoods.getComplementGoodsIdList().split(",").length;
            BigDecimal complementPrice = nowGoods.getGroupPurchasePrice();
            Map<Integer, BigDecimal> complementGoodsPrice = new HashMap<>();
            complementGoodsPrice.put(nowGoods.getId(), nowGoods.getGroupPurchasePrice());
            if (nowGoods.getComplementGoodsIdList() != null) {
                List<Goods> complementGoodies = goodsDao.findGoodsByIds(nowGoods.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 (!goodsId.equals(sellOrder.getParentGoodsId()) && !goodsId.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(goodsBalance).divide(complementPrice, 2, BigDecimal.ROUND_DOWN);
                }
                complementGoodsNum = complementGoodsNum - sellOrder.getNum();
                if (complementGoodsNum <= 0) {
                    sellOrderExpectAmount = expectAmount.subtract(hasRouteSellOrderExpectAmount);
                    sellOrderBalance = goodsBalance.subtract(hasRouteSellOrderBalance);
                }
                hasRouteSellOrderExpectAmount = hasRouteSellOrderExpectAmount.add(sellOrderExpectAmount);
                hasRouteSellOrderBalance = hasRouteSellOrderBalance.add(sellOrderBalance);

                sellOrder.setExpectAmount(sellOrderExpectAmount);
                sellOrder.setBalanceAmount(sellOrderBalance);
                sellOrder.setActualAmount(sellOrderExpectAmount.subtract(sellOrderBalance));
                sellOrder.setOrganId(order.getOrganId());
                sellOrder.setCooperationOrganId(musicGroup.getCooperationOrganId());
                sellOrder.setEduTeacherId(musicGroup.getEducationalTeacherId());
                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;
    }
}
