package com.xxfc.platform.order.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.github.wxiaoqi.security.admin.constant.enumerate.MemberEnum;
import com.github.wxiaoqi.security.admin.feign.UserFeign;
import com.github.wxiaoqi.security.admin.feign.dto.AppUserDTO;
import com.github.wxiaoqi.security.common.constant.CommonConstants;
import com.github.wxiaoqi.security.common.exception.BaseException;
import com.github.wxiaoqi.security.common.msg.ObjectRestResponse;
import com.github.wxiaoqi.security.common.util.process.ResultCode;
import com.xxfc.platform.activity.entity.Coupon;
import com.xxfc.platform.activity.feign.ActivityFeign;
import com.xxfc.platform.order.biz.*;
import com.xxfc.platform.order.biz.inner.OrderCalculateBiz;
import com.xxfc.platform.order.contant.enumerate.ItemTypeEnum;
import com.xxfc.platform.order.contant.enumerate.OrderCostEnum;
import com.xxfc.platform.order.contant.enumerate.OrderStatusEnum;
import com.xxfc.platform.order.contant.enumerate.OrderTypeEnum;
import com.xxfc.platform.order.entity.*;
import com.xxfc.platform.order.pojo.OrderAccompanyDTO;
import com.xxfc.platform.order.pojo.dto.CompanyWalletDetailDTO;
import com.xxfc.platform.order.pojo.order.RentVehicleBO;
import com.xxfc.platform.order.pojo.order.VehicleItemDTO;
import com.xxfc.platform.order.pojo.price.RentVehiclePriceVO;
import com.xxfc.platform.universal.constant.DictionaryKey;
import com.xxfc.platform.universal.feign.ThirdFeign;
import com.xxfc.platform.vehicle.common.RestResponse;
import com.xxfc.platform.vehicle.constant.AccompanyingItemType;
import com.xxfc.platform.vehicle.entity.*;
import com.xxfc.platform.vehicle.entity.BranchCompany;
import com.xxfc.platform.vehicle.feign.VehicleFeign;
import com.xxfc.platform.vehicle.pojo.RentVehicleBookDTO;
import com.xxfc.platform.vehicle.pojo.dto.VehicleModelCalendarPriceDTO;
import com.xxfc.platform.vehicle.pojo.dto.order.VMCalendarPriceCostDTO;
import com.xxfc.platform.vehicle.pojo.vo.AccompanyingItemVo;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.github.wxiaoqi.security.common.constant.CommonConstants.SYS_FALSE;
import static com.github.wxiaoqi.security.common.constant.CommonConstants.SYS_TRUE;
import static com.xxfc.platform.order.contant.enumerate.ItemTypeEnum.ACCOMPANY;
import static com.xxfc.platform.order.entity.OrderPersonInsurance.STATUS_PAY;
import static com.xxfc.platform.order.entity.OrderPersonInsurance.STATUS_TOPAY;
import static com.xxfc.platform.order.pojo.order.add.AddRentVehicleDTO.GOODS_DEPOSIT_TYPE_UP;
import static com.xxfc.platform.universal.constant.DictionaryKey.APP_ORDER;

@Service
@Slf4j
public class OrderRentVehicleService extends AbstractOrderHandle<OrderRentVehicleBiz, RentVehicleBO> {

    private static BigDecimal DRIVER_PRICE;
    private static BigDecimal DAMAGE_SAFE;
    private static Integer DRIVER_TYPE_COMPANY = 1;
    private static Integer DRIVER_TYPE_DAMAGE_SAFE = 1;
    private static Integer DISCOUNT_STATUS_NONE = 0;
    private static Integer DISCOUNT_STATUS_MEMBER = 1;
    private static Integer DISCOUNT_STATUS_FIXED = 2;
    private static Long autoCancelTime;

    @Autowired
    VehicleFeign vehicleFeign;

    @Autowired
    OrderCostDetailBiz orderCostDetailBiz;

    @Autowired
    OrderTemplateBiz orderTemplateBiz;

    @Autowired
    ThirdFeign thirdFeign;

    @Autowired
    ActivityFeign activityFeign;

    @Autowired
    OrderCalculateBiz orderCalculateBiz;

    @Autowired
    OrderAccountBiz orderAccountBiz;


    @Autowired
    OrderPersonInsuranceBiz orderPersonInsuranceBiz;

    @PostConstruct
    public void init(){
        this.channel = Coupon.CHANNEL_RENT;
        this.orderTypeEnum = OrderTypeEnum.RENT_VEHICLE;
    }

    /**
     * 创建订单及其子项 （需求预定申请）
     * @param detail
     */
    public void applyCreateOrder(RentVehicleBO detail, String orderNo) {
        //初始化
        applyInitDetail(detail, orderNo);
        //计算价格
        handleCalculate(detail);
        //插入baseOrder
        baseOrderBiz.insertSelective(detail.getOrder());
        //处理detail
        handleDetail(detail);
    }

    /**
     * 创建订单及其子项（特惠租车）
     * @param detail
     */
    public void specialCreateOrder(RentVehicleBO detail, String orderNo) {
        //初始化
        specialInitDetail(detail, orderNo);
        //计算价格
        handleCalculate(detail);
        //插入baseOrder
        baseOrderBiz.insertSelective(detail.getOrder());
        //处理detail
        handleDetail(detail);
    }

    public void applyInitDetail(RentVehicleBO bo, String orderNo) {
        BaseOrder order = createBaseOrder(bo.getOrderOrigin(), bo.getFacilitatePhone(), bo.getAppUserDTO(), orderNo);
        bo.setOrder(order);
        initDetailSecond(bo);
    }

    public void specialInitDetail(RentVehicleBO bo, String orderNo) {
        BaseOrder order = createBaseOrder(bo.getOrderOrigin(), bo.getFacilitatePhone(), bo.getAppUserDTO(), orderNo);
        bo.setOrder(order);
        initDetailSecond(bo);
    }

//    public void specialInitDetail(RentVehicleBO bo, String orderNo) {
//        BaseOrder order = createBaseOrder(bo.getOrderOrigin(), bo.getFacilitatePhone(), bo.getAppUserDTO(), orderNo);
//        bo.setOrder(order);
//        initDetailSecond(bo);
//    }

    @Override
    public void initDetail(RentVehicleBO bo) {
        super.initDetail(bo);
        initDetailSecond(bo);
    }

    public void initDetailSecond(RentVehicleBO bo) {
        CompanyWalletDetailDTO companyWalletDetailDTO = new CompanyWalletDetailDTO();
        //下单
        companyWalletDetailDTO.setClosedVehicleAmout(BigDecimal.ZERO);//收车服务费
        companyWalletDetailDTO.setPlatformCompanyId(0);//平台门店
        companyWalletDetailDTO.setOrderExtract(BigDecimal.ZERO);//订单抽成比例
        companyWalletDetailDTO.setPlatformExtract(BigDecimal.ZERO);//平台抽成比例
        companyWalletDetailDTO.setVehicleExtract(BigDecimal.ZERO);//车辆收益比例


        initDictionary();
//        VehicleModel vehicleModel = vehicleFeign.get(bo.getModelId()).getData();
//        bo.setVehicleModel(vehicleModel);
        //根据还车城市设置还车公司id
        if(SYS_FALSE.equals(bo.getEndCompanyId())) {
            if(null != bo.getEndCity() && null != bo.getStartCity()) {
                if(bo.getEndCity().equals(bo.getStartCity())) {
                    bo.setEndCompanyId(bo.getStartCompanyId());
                }else {
                    //查询结束城市分公司
                    List<BranchCompany> companyDetails = vehicleFeign.branchCompanyEntityList(
                            BeanUtil.beanToMap(new BranchCompany(){{
                                setAddrCity(bo.getEndCity());
                            }}, false, true)).getData();

                    if(null != companyDetails && companyDetails.size() > 0) {
                        bo.setEndCompanyId(companyDetails.get(0).getId());
                    }
                }
            }
        }

        //设置新增字段
            //开始公司（门店）
        if(null != bo.getStartCompanyId()) {
            List<BranchCompany> companyDetails = vehicleFeign.branchCompanyEntityList(
                    BeanUtil.beanToMap(new BranchCompany(){{
                        setId(bo.getStartCompanyId());
                    }}, false, true)).getData();

            if(null != companyDetails && companyDetails.size() > 0) {
                bo.setStartBranchId(companyDetails.get(0).getCompanyId());
            }
        }

        //结束公司（门店）
        if(null != bo.getEndCompanyId()) {
            List<BranchCompany> companyDetails = vehicleFeign.branchCompanyEntityList(
                    BeanUtil.beanToMap(new BranchCompany(){{
                        setId(bo.getEndCompanyId());
                    }}, false, true)).getData();

            if(null != companyDetails && companyDetails.size() > 0) {
                bo.setEndBranchId(companyDetails.get(0).getCompanyId());
            }
        }

        //所属公司（门店）商品类型
        if(null != bo.getVehicleId()) {
            Vehicle vehicle = vehicleFeign.get(bo.getVehicleId()).getData();
            bo.setVehicleCompanyId(vehicle.getSubordinateBranch());
            bo.setVehicleManageCompanyId(vehicle.getManageCompanyId());

            List<BranchCompany> companyDetails = vehicleFeign.branchCompanyEntityList(
                    BeanUtil.beanToMap(new BranchCompany(){{
                        setId(bo.getVehicleCompanyId());
                    }}, false, true)).getData();

            if(null != companyDetails && companyDetails.size() > 0) {
                bo.setVehicleBranchId(companyDetails.get(0).getCompanyId());
            }

            List<BranchCompany> companyDetails2 = vehicleFeign.branchCompanyEntityList(
                    BeanUtil.beanToMap(new BranchCompany(){{
                        setId(bo.getVehicleManageCompanyId());
                    }}, false, true)).getData();

            if(null != companyDetails2 && companyDetails2.size() > 0) {
                bo.setVehicleManageBranchId(companyDetails2.get(0).getCompanyId());
            }

            //商品类型
            bo.getOrder().setGoodsType(vehicle.getGoodsType());
            bo.setVehicle(vehicle);
            bo.setGoodsDepositType(vehicle.getDepositType());
        }
    }

    public void initDictionary() {
        dictionaryMap = thirdFeign.dictionaryGetAll4Map().getData();
        log.info("out getAll4Map"+ System.currentTimeMillis());
        this.autoCancelTime = Long.valueOf(dictionaryMap.get(APP_ORDER+ "_"+ DictionaryKey.ACT_RENT).getDetail());
        this.DRIVER_PRICE = new BigDecimal(dictionaryMap.get(APP_ORDER+ "_"+ DictionaryKey.DRIVER_PRICE).getDetail());
        this.DAMAGE_SAFE = new BigDecimal(dictionaryMap.get(APP_ORDER+ "_"+ DictionaryKey.DAMAGE_SAFE).getDetail());

    }

    @Override
    public void handleDetail(RentVehicleBO bo) {
        //设置订单状态为3
        bo.getOrder().setStatus(OrderStatusEnum.ORDER_UNPAY.getCode());
        //设置订单图片

        bo.getOrder().setPicture(StrUtil.isNotBlank(bo.getVehicle().getCover())? bo.getVehicle().getCover(): bo.getVehicle().getPicture());
        //设置订单名称
        bo.getOrder().setName(bo.getVehicle().getName());

        //分布式事务执行标记
        Integer cloudTransact = 0;

        try{
            //插入随声物品item
            List<OrderAccompanyDTO> oads = new ArrayList<OrderAccompanyDTO>();
            List<AccompanyingItemVo> accompanyingItemList = vehicleFeign.listAccompanyingItem().getData();
//        Map<String, AccompanyingItemVo> accompanyingItemMap = vehicleFeign.listAccompanyingItem().getData()
//                .parallelStream().collect(Collectors.toMap(en -> en.getId().toString(), en -> en));
            if(null == bo.getAccompanyItems()) {
                bo.setAccompanyItems(new ArrayList<OrderAccompanyDTO>());
            }
            Map<String, OrderAccompanyDTO> orderAccompanyDTOMap = bo.getAccompanyItems()
                    .parallelStream().collect(Collectors.toMap(en -> en.getId().toString(), en -> en));

            for(AccompanyingItemVo aiv : accompanyingItemList) {
                if(AccompanyingItemType.TOOL.getCode().equals(aiv.getType())
                        || AccompanyingItemType.EQUIPMENT.getCode().equals(aiv.getType())) {
                    OrderAccompanyDTO orderAccompanyDTO = BeanUtil.toBean(aiv, OrderAccompanyDTO.class);
                    orderAccompanyDTO.setUnitPrice(aiv.getPrice());
                    orderAccompanyDTO.setNum(aiv.getNumber());
                    oads.add(orderAccompanyDTO);
                }else {
                    OrderAccompanyDTO orderAccompanyDTO = orderAccompanyDTOMap.get(aiv.getId().toString());
                    if(null != orderAccompanyDTO) {
                        BeanUtil.copyProperties(aiv, orderAccompanyDTO);
                        orderAccompanyDTO.setUnitPrice(aiv.getPrice());
                        oads.add(orderAccompanyDTO);
                    }
                }
            }
            bo.setAccompanyItems(oads);

            if(BaseOrder.ORDER_SIGN_NORMAL == bo.getOrderSign()) {
                //获取可用车辆(创建排班记录)
                acquireVehicle(bo, null, null);
                cloudTransact = 1;
            }

            //添加随声物品项
            OrderItem accompanyItem = orderItemBiz.initOrderItem(BigDecimal.ZERO, 1, "随车物品", null, ACCOMPANY);
            accompanyItem.setRealAmount(BigDecimal.ZERO);
            accompanyItem.setDetail(JSONUtil.toJsonStr(bo.getAccompanyItems()));
            accompanyItem.setOrderId(bo.getOrder().getId());
            orderItemBiz.insertSelective(accompanyItem);

            //是否有使用会员权益 则调用接口触发新增消费记录次数
            //扣减免费天数
            useOrBackFreeDays(bo, UserFeign.MEMBER_DAYS_LOCK);
            cloudTransact = 2;

            OrderItem vehicleModelItem = bo.getItemByTypeEnum(ItemTypeEnum.VEHICLE_MODEL);
            BigDecimal amount = vehicleModelItem.getTotalAmount();

            //如果有使用优惠券，则扣减
            if(BigDecimal.ZERO.compareTo(bo.getOrder().getCouponAmount()) < 0) {
                activityFeign.use(bo.getAppUserDTO().getUserid(), Convert.toList(String.class, bo.getOrder().getCouponTickerNos()), bo.getOrder().getNo(), channel, amount, ActivityFeign.TYPE_USE);
            }
            cloudTransact = 3;

            //设置后台系统创建人
            if(StrUtil.isNotBlank(bo.getCrtUser())) {
                bo.getOrder().setCrtUser(bo.getCrtUser());
            }

            //
            bo.setMetaEndTime(bo.getEndTime());

            //插入人身保险列表
            if(SYS_TRUE == bo.getNeedPersonInsurance()){
                bo.getOrder().setInsureStatus(SYS_TRUE);
                for(OrderPersonInsurance opi : bo.getConfirmInsurances()) {
                    opi.setOrderId(bo.getOrder().getId());
                    opi.setOrderNo(bo.getOrder().getNo());
                    orderPersonInsuranceBiz.insertSelective(opi);
                }
            }

            /**
             * 处理订单详情
             * 1、补充baseorder 信息 update
             * 2、插入item
             * 3、判断是否支付
             * @param detail
             */
            super.handleDetail(bo);
        }catch (Exception e) {
            //事务补偿处理
            log.error("cloudTransact : {}", cloudTransact);
            RestResponse<Integer> restResponse;
            try {
                //判断分布式事务执行到哪里
                switch (cloudTransact) {
                    case 1 :
                        if(BaseOrder.ORDER_SIGN_NORMAL == bo.getOrderSign()) {
                            //取消车辆预定
                            //未支付，拒绝之前的预约
                            errorRejectVehicle(bo);
                        }

                        break;
                    case 2 :
                        if(BaseOrder.ORDER_SIGN_NORMAL == bo.getOrderSign()) {
                            //取消车辆预定
                            //未支付，拒绝之前的预约
                            errorRejectVehicle(bo);
                        }
                        useOrBackFreeDays(bo, UserFeign.MEMBER_DAYS_WITHDRAW);

                        break;
                    case 3 :
                        if(BaseOrder.ORDER_SIGN_NORMAL == bo.getOrderSign()) {
                            //取消车辆预定
                            //未支付，拒绝之前的预约
                            errorRejectVehicle(bo);
                        }

                        //退还天数
                        useOrBackFreeDays(bo, UserFeign.MEMBER_DAYS_WITHDRAW);

                        //退还优惠券
                        for(String backCoupon : Convert.toList(String.class, bo.getOrder().getCouponTickerNos())) {
                            activityFeign.cancelUse(backCoupon);
                        }
                        break;
                    default:
                        break;
                }
            } catch (Exception ex) {
                 log.error(ex.getMessage(), ex);
            } finally {
                throw e;
            }
        }


        //发送定时取消订单(数据字典设置--5分钟)
        rabbitProduct.sendDelayMessage(bo.getOrder(), autoCancelTime);
    }

    private void useOrBackFreeDays(RentVehicleBO bo, int memberDaysWithdraw) {
        //退还天数
        if (SYS_TRUE.equals(bo.getOrder().getHasMemberRight())) {
            if (null == bo.getFreeDays()) {
                bo.setFreeDays(0);
            }
            int result = userFeign.memberDays(bo.getAppUserDTO().getUserid(), bo.getFreeDays(), memberDaysWithdraw);
            if (result < 0) {
                throw new BaseException(ResultCode.FAILED_CODE);
            }
        }
    }

    public void errorRejectVehicle(RentVehicleBO bo) {
        //取消车辆预定
        //未支付，拒绝之前的预约
        RestResponse<Integer> restResponse = vehicleFeign.rentRejectVehicleBooking(bo.getBookRecordId());
        log.info("下单失败，拒绝预约{}, 结果: {}", bo.getBookRecordId(), restResponse.toString());
    }

    @Override
    public void handleCalculate(RentVehicleBO bo) {
        RentVehiclePriceVO rvpv = calculatePrice(bo);
        BeanUtil.copyProperties(rvpv, bo.getOrder());
        BeanUtil.copyProperties(rvpv, bo);
    }

    @Override
    public RentVehiclePriceVO calculatePrice(RentVehicleBO detail) {
        if(Vehicle.PRICE_TYPE_HOUR ==  detail.getVehicle().getPriceType()) {
            return hourCalculatePrice(detail);
        }else {
            return dayCalculatePrice(detail);
        }
    }


    private RentVehiclePriceVO dayCalculatePrice(RentVehicleBO detail) {
        RentVehiclePriceVO rvp = new RentVehiclePriceVO();
        BigDecimal realAmount = BigDecimal.ZERO;
        BigDecimal orderAmount = BigDecimal.ZERO;
        BigDecimal goodsAmount = BigDecimal.ZERO;
        BigDecimal vehicleAmount = BigDecimal.ZERO;
        BigDecimal metaVehicleAmount = BigDecimal.ZERO;
        BigDecimal driverAmount = BigDecimal.ZERO;
        BigDecimal damageSafeAmount = BigDecimal.ZERO;
        BigDecimal personInsuranceAmount = BigDecimal.ZERO;
        BigDecimal couponAmount = BigDecimal.ZERO;
        BigDecimal depositAmount = BigDecimal.ZERO;
        String couponDesc = "";
        Integer vehicleDayNum = 0;
        Integer freeDayNum = 0;
        //抵消的天数
        Integer offsetNum = 0;

        //当前用户
        AppUserDTO dto = detail.getAppUserDTO();

        //车型信息
        Vehicle vehicle = detail.getVehicle();

        detail.initDate();
        List<VehicleModelCalendarPriceDTO> metaVmcpds = vehicleFeign.getPriceByVehicleIdFeignV2(detail.getVehicleId(), detail.getStartTime(), detail.getEndTime(), dto.getUserid()).getData();

        if(null != detail.getSpecialUnitPrice()) {
            metaVmcpds.forEach(meta -> {
                meta.setPrice(detail.getSpecialUnitPrice());
            });
        }
        List<VMCalendarPriceCostDTO> vmcpds = Convert.toList(VMCalendarPriceCostDTO.class, metaVmcpds);


        //设置Item
        VehicleItemDTO vehicleOrderItem = BeanUtil.toBean(
                orderItemBiz.initOrderItem(vehicle.getPrice(), detail.getDayNum(), vehicle.getName()
                        , vehicle.getId(), ItemTypeEnum.VEHICLE_MODEL, JSONUtil.parseArray(vmcpds).toString())
                , VehicleItemDTO.class);
        OrderItem driverOrderItem = orderItemBiz.initOrderItem(DRIVER_PRICE, detail.getDayNum(), "平台司机", null, ItemTypeEnum.DRIVER);
        OrderItem damageSafeOrderItem = orderItemBiz.initOrderItem(DAMAGE_SAFE, detail.getDayNum(), "免赔费用", null, ItemTypeEnum.DAMAGE_SAFE);

        detail.setItems(new ArrayList<OrderItem>());
        detail.getItems().add(vehicleOrderItem);

        //如果用户存在，免费天数
        if(null != dto && null != detail.getRentFreeDay() && detail.getRentFreeDay() > 0 ) {
            if(null == dto.getRentFreeDays() || dto.getRentFreeDays() <= 0) {
                throw new BaseException(ResultCode.PARAM_EPIRE_CODE, new HashSet<String>() {{
                    add("免费租车天数不存在或为0");
                }});
            }

//            //循环价格列表 获得对应消耗的免费天数
            vehicleOrderItem.initDetail(dto.getRentFreeDays());
            freeDayNum = vehicleOrderItem.getCutNum();
            offsetNum = vehicleOrderItem.getOffsetNum();
            vehicleDayNum = detail.getDayNum() - offsetNum;
            detail.getOrder().setHasMemberRight(SYS_TRUE);
        }else {
            vehicleOrderItem.initDetail(0);
            vehicleDayNum = detail.getDayNum();
        }

        vmcpds = vehicleOrderItem.getVehicleDetail();
        detail.setFreeDays(freeDayNum);

        //计算价格
        //计算车辆费用

        //如果用户存在，并且为会员，并且车辆有优惠价
        //默认折扣默认100
        detail.setRebate(100);
//        if(null != dto && SYS_TRUE.equals(dto.getIsMember()) && !NONE.getCode().equals(dto.getMemberLevel()) && !DISCOUNT_STATUS_NONE.equals(vehicleModel.getRentDiscountStatus())) {
//            String[] prices = StrUtil.isBlank(vehicleModel.getRentDiscountPrice())
//                    ?new String[]{vehicleModel.getPrice().toString(),vehicleModel.getPrice().toString(),vehicleModel.getPrice().toString()}
//                    :vehicleModel.getRentDiscountPrice().split(",");
//            //设置是否使用会员权益
//            for(VMCalendarPriceCostDTO vmcpcd : vehicleOrderItem.getVehicleDetail()) {
//                if(!vmcpcd.getNo_discount_price().equals(vmcpcd.getPrice())) {
//                    detail.getOrder().setHasMemberRight(SYS_TRUE);
//                    break;
//                }
//            }
//
//            detail.setRebate(dto.getDiscount());
//        }

        //计算价格
        if(vehicleDayNum > 0) {
            for(int i = offsetNum; i < vmcpds.size(); i++) {
                vehicleAmount = vehicleAmount.add(vmcpds.get(i).getConsumeAmount());
                metaVehicleAmount = metaVehicleAmount.add(vmcpds.get(i).getNo_discount_price());
            }
        }else {
            vehicleOrderItem.setUnitPrice(BigDecimal.ZERO);
        }

        //如果有使用会员权益或者优惠券，则设置订单已优惠
        if(SYS_TRUE.equals(detail.getOrder().getHasMemberRight())) {
            detail.getOrder().setHasDiscount(SYS_TRUE);
        }

        //平均单价 = 总价 / 实际消费天数
        vehicleOrderItem.calculateVehicleUnitPrice(vehicleAmount, metaVehicleAmount, Boolean.TRUE);

        if(DRIVER_TYPE_COMPANY.equals(detail.getDriverType())) {
            //计算司机费用
            driverAmount = driverAmount.add(driverOrderItem.getCalculateAmount(Boolean.TRUE));
            detail.getItems().add(driverOrderItem);
        }

        if(DRIVER_TYPE_DAMAGE_SAFE.equals(detail.getDamageSafe())) {
            //免赔费用
            damageSafeAmount = damageSafeAmount.add(damageSafeOrderItem.getCalculateAmount(Boolean.TRUE));
            detail.getItems().add(damageSafeOrderItem);
        }

        if(SYS_TRUE == detail.getNeedPersonInsurance() && CollUtil.isNotEmpty(detail.getInsurances())) {
            rvp.setNeedPersonInsurance(SYS_TRUE);
            OrderPersonInsurance metaopi = new OrderPersonInsurance();
            //计算天数
            orderAccountBiz.calculatePersonInsurance(detail.getStartTime(), detail.getEndTime(), metaopi);
            if(STATUS_TOPAY == metaopi.getStatus()) {
                for(OrderPersonInsurance opi : detail.getInsurances()) {
                    opi.setOrderDay(detail.getDayNum());
                    opi.setAmount(metaopi.getAmount());
                    opi.setStatus(metaopi.getStatus());
                    opi.setInsuranceDay(metaopi.getInsuranceDay());
                    opi.setStartTime(metaopi.getStartTime());
                    opi.setEndTime(metaopi.getEndTime());

                    detail.getConfirmInsurances().add(BeanUtil.toBean(opi, OrderPersonInsurance.class));
                    personInsuranceAmount = personInsuranceAmount.add(opi.getAmount());
                }
                OrderItem personInsuranceOrderItem = orderItemBiz.initOrderItem(metaopi.getAmount(), detail.getConfirmInsurances().size(), "人身保险", null, ItemTypeEnum.PERSON_INSURANCE, JSONUtil.toJsonStr(metaopi));
                personInsuranceOrderItem.getCalculateAmount(true);
                rvp.setPersonInsureNum(personInsuranceOrderItem.getBuyNum());
                rvp.setPersonInsurePrice(metaopi.getAmount());
                rvp.setPersonInsureAmount(personInsuranceOrderItem.getRealAmount());
                detail.getItems().add(personInsuranceOrderItem);
            }else {
                throw new BaseException("人身保险信息不正确", ResultCode.PARAM_ILLEGAL_CODE);
            }
        }

        //商品价格
        goodsAmount = goodsAmount.add(vehicleAmount).add(driverAmount).add(damageSafeAmount).add(personInsuranceAmount);

        //vehicleAmount 优惠券处理
        if(null != detail.getTickerNo() && detail.getTickerNo().size() > 0) {
            List<String> usedTickerNos = CollUtil.newArrayList();
            for(String no : detail.getTickerNo()) {
                BigDecimal tempCouponAmount = activityFeign.use(dto.getUserid(),  CollUtil.newArrayList(no), detail.getOrder().getNo(), channel, vehicleAmount, ActivityFeign.TYPE_NO_USE);
                if(tempCouponAmount.compareTo(BigDecimal.ZERO) > 0) {
                    //加入总couponAmount
                    couponAmount = couponAmount.add(tempCouponAmount);
                    usedTickerNos.add(no);

                    //设置描述
                    couponDesc += activityFeign.info(no).getTitle();
                }
            }

            if(couponAmount.compareTo(BigDecimal.ZERO) > 0) {
                detail.getOrder().setCouponTickerNos(usedTickerNos.stream().collect(Collectors.joining(",")));
                detail.getOrder().setHasDiscount(SYS_TRUE);
                vehicleOrderItem.handleCouponAmount(couponAmount);
            }
        }

        //总价格（包含押金）
        //判断商品押金方式
        detail.setVehicleDeposit(vehicle.getDeposit());
        detail.setTrafficDeposit(vehicle.getVioDeposit());
        detail.setReturnPayResidue(vehicle.getVioDeposit());
        if(GOODS_DEPOSIT_TYPE_UP == detail.getGoodsDepositType()) {
            depositAmount = depositAmount.add(detail.getVehicleDeposit()).add(detail.getTrafficDeposit());
        }else {
            depositAmount = depositAmount.add(detail.getTrafficDeposit());
        }
        orderAmount = orderAmount.add(goodsAmount).add(depositAmount);
        realAmount = orderAmount.subtract(couponAmount);

        //生成订单明细
        rvp.setOrderSign(detail.getOrderSign());
        rvp.setPriceType(vehicle.getPriceType());
        rvp.setDeposit(depositAmount);
        rvp.setDriverPrice(DRIVER_PRICE);
        rvp.setDamageSafePrice(DAMAGE_SAFE);
        rvp.setModelName(vehicle.getName());
        rvp.setDayNum(detail.getDayNum());
        rvp.setVehicleNum(1);
        rvp.setDriverNum(1);
        rvp.setCouponAmount(couponAmount);
        rvp.setOrderAmount(orderAmount);
        rvp.setGoodsAmount(goodsAmount);
        rvp.setRealAmount(realAmount);
        rvp.setDriverAmount(driverAmount);
        rvp.setVehicleAmount(vehicleAmount);
        rvp.setDamageSafeAmount(damageSafeAmount);
        rvp.setModelAmount(vehicleOrderItem.getUnitPrice());
        rvp.setVehicleDayNum(vehicleDayNum);

        rvp.setFreeDayNum(freeDayNum);
        rvp.setCutDayNum(offsetNum);
        rvp.setFreeAmount(vehicleOrderItem.getCutAmount());
        rvp.setBuyVehicleAmount(vehicleOrderItem.getBuyAmount());
        rvp.setRealVehicleAmount(vehicleOrderItem.getRealAmount());
        rvp.setCouponDesc(couponDesc);
        rvp.setUseAmountList(vehicleOrderItem.getVehicleDetail());
        rvp.setSameUnitPrice(vehicleOrderItem.getSameUnitPrice());

        rvp.initParamJson();
        //设置收费明细
        costDetail(rvp, handleChildren(detail));
        return rvp;
    }

    private RentVehiclePriceVO hourCalculatePrice(RentVehicleBO detail) {
        BigDecimal realAmount = BigDecimal.ZERO;
        BigDecimal orderAmount = BigDecimal.ZERO;
        BigDecimal goodsAmount = BigDecimal.ZERO;
        BigDecimal vehicleAmount = BigDecimal.ZERO;
        BigDecimal metaVehicleAmount = BigDecimal.ZERO;
        BigDecimal driverAmount = BigDecimal.ZERO;
        BigDecimal damageSafeAmount = BigDecimal.ZERO;
        BigDecimal personInsuranceAmount = BigDecimal.ZERO;
        BigDecimal couponAmount = BigDecimal.ZERO;
        BigDecimal depositAmount = BigDecimal.ZERO;
        String couponDesc = "";
        Integer vehicleHourNum = 0;
        Integer freeHourNum = 0;
        //抵消的天数
        Integer offsetNum = 0;

        //当前用户
        AppUserDTO dto = detail.getAppUserDTO();
//
//        //车型信息
//        VehicleModel vehicleModel = vehicleFeign.get(detail.getModelId()).getData();

        //车辆信息
        Vehicle vehicle = detail.getVehicle();

        detail.initDate();
        List<VehicleModelCalendarPriceDTO> metaVmcpds = vehicleFeign.getPriceByVehicleIdFeignV2(detail.getVehicleId(), detail.getStartTime(), detail.getEndTime(), dto.getUserid()).getData();

        if(null != detail.getSpecialUnitPrice()) {
            metaVmcpds.forEach(meta -> {
                meta.setPrice(detail.getSpecialUnitPrice());
            });
        }
        List<VMCalendarPriceCostDTO> vmcpds = Convert.toList(VMCalendarPriceCostDTO.class, metaVmcpds);


        //设置Item
        VehicleItemDTO vehicleOrderItem = BeanUtil.toBean(
                orderItemBiz.initOrderItem(vehicle.getPrice(), detail.getDayNum(), vehicle.getName()
                        , vehicle.getId(), ItemTypeEnum.VEHICLE_MODEL, JSONUtil.parseArray(vmcpds).toString())
                , VehicleItemDTO.class);
        OrderItem driverOrderItem = orderItemBiz.initOrderItem(DRIVER_PRICE, detail.getDayNum(), "平台司机", null, ItemTypeEnum.DRIVER);
        OrderItem damageSafeOrderItem = orderItemBiz.initOrderItem(DAMAGE_SAFE, detail.getDayNum(), "免赔费用", null, ItemTypeEnum.DAMAGE_SAFE);

        detail.setItems(new ArrayList<OrderItem>());
        detail.getItems().add(vehicleOrderItem);

        vehicleOrderItem.initDetail();
        vmcpds = vehicleOrderItem.getVehicleDetail();
        vehicleHourNum = detail.getHourNum();

        //计算价格
        //计算车辆费用

        //如果用户存在，并且为会员，并且车辆有优惠价
        //默认折扣默认100
        detail.setRebate(100);

        //计算价格
        if(vehicleHourNum > 0) {
            for(int i = offsetNum; i < vmcpds.size(); i++) {
                vehicleAmount = vehicleAmount.add(vmcpds.get(i).getConsumeAmount());
                metaVehicleAmount = metaVehicleAmount.add(vmcpds.get(i).getNo_discount_price());
            }
        }else {
            vehicleOrderItem.setUnitPrice(BigDecimal.ZERO);
        }

        //如果有使用会员权益或者优惠券，则设置订单已优惠
        if(SYS_TRUE.equals(detail.getOrder().getHasMemberRight())) {
            detail.getOrder().setHasDiscount(SYS_TRUE);
        }

        //平均单价 = 总价 / 实际消费天数
        vehicleOrderItem.calculateVehicleUnitPrice(vehicleAmount, metaVehicleAmount, Boolean.TRUE);

        if(DRIVER_TYPE_COMPANY.equals(detail.getDriverType())) {
            //计算司机费用
            driverAmount = driverAmount.add(driverOrderItem.getCalculateAmount(Boolean.TRUE));
            detail.getItems().add(driverOrderItem);
        }

        if(DRIVER_TYPE_DAMAGE_SAFE.equals(detail.getDamageSafe())) {
            //免赔费用
            damageSafeAmount = damageSafeAmount.add(damageSafeOrderItem.getCalculateAmount(Boolean.TRUE));
            detail.getItems().add(damageSafeOrderItem);
        }

        if(SYS_TRUE == detail.getNeedPersonInsurance() && CollUtil.isNotEmpty(detail.getInsurances())) {
            for(OrderPersonInsurance opi : detail.getInsurances()) {
                opi.setOrderDay(detail.getDayNum());
                //计算天数
                orderAccountBiz.calculatePersonInsurance(detail.getStartTime(), detail.getEndTime(), opi);
                if(STATUS_TOPAY == opi.getStatus()) {
                    detail.getConfirmInsurances().add(BeanUtil.toBean(opi, OrderPersonInsurance.class));
                    OrderItem personInsuranceOrderItem = orderItemBiz.initOrderItem(opi.getAmount(), 1, "人身保险", null, ItemTypeEnum.PERSON_INSURANCE, JSONUtil.toJsonStr(opi));
                    detail.getItems().add(personInsuranceOrderItem);
                    personInsuranceAmount = personInsuranceAmount.add(personInsuranceOrderItem.getCalculateAmount(Boolean.TRUE));
                }
            }
        }

        //商品价格
        goodsAmount = goodsAmount.add(vehicleAmount).add(driverAmount).add(damageSafeAmount).add(personInsuranceAmount);

        //vehicleAmount 优惠券处理
        if(null != detail.getTickerNo() && detail.getTickerNo().size() > 0) {
            List<String> usedTickerNos = CollUtil.newArrayList();
            for(String no : detail.getTickerNo()) {
                BigDecimal tempCouponAmount = activityFeign.use(dto.getUserid(),  CollUtil.newArrayList(no), detail.getOrder().getNo(), channel, vehicleAmount, ActivityFeign.TYPE_NO_USE);
                if(tempCouponAmount.compareTo(BigDecimal.ZERO) > 0) {
                    //加入总couponAmount
                    couponAmount = couponAmount.add(tempCouponAmount);
                    usedTickerNos.add(no);

                    //设置描述
                    couponDesc += activityFeign.info(no).getTitle();
                }
            }

            if(couponAmount.compareTo(BigDecimal.ZERO) > 0) {
                detail.getOrder().setCouponTickerNos(usedTickerNos.stream().collect(Collectors.joining(",")));
                detail.getOrder().setHasDiscount(SYS_TRUE);
                vehicleOrderItem.handleCouponAmount(couponAmount);
            }
        }

        //总价格（包含押金）
        //判断商品押金方式
        detail.setVehicleDeposit(vehicle.getDeposit());
        detail.setTrafficDeposit(vehicle.getVioDeposit());
        detail.setReturnPayResidue(vehicle.getVioDeposit());
        if(GOODS_DEPOSIT_TYPE_UP == detail.getGoodsDepositType()) {
            depositAmount = depositAmount.add(detail.getVehicleDeposit()).add(detail.getTrafficDeposit());
        }else {
            depositAmount = depositAmount.add(detail.getTrafficDeposit());
        }
        orderAmount = orderAmount.add(goodsAmount).add(depositAmount);
        realAmount = orderAmount.subtract(couponAmount);

        //生成订单明细
        RentVehiclePriceVO rvp = new RentVehiclePriceVO();
        rvp.setOrderSign(detail.getOrderSign());
        rvp.setPriceType(vehicle.getPriceType());
        rvp.setDeposit(depositAmount);
        rvp.setDriverPrice(DRIVER_PRICE);
        rvp.setDamageSafePrice(DAMAGE_SAFE);
        rvp.setModelName(vehicle.getName());
        rvp.setHourNum(detail.getHourNum());
        rvp.setVehicleNum(1);
        rvp.setDriverNum(1);
        rvp.setCouponAmount(couponAmount);
        rvp.setOrderAmount(orderAmount);
        rvp.setGoodsAmount(goodsAmount);
        rvp.setRealAmount(realAmount);
        rvp.setDriverAmount(driverAmount);
        rvp.setVehicleAmount(vehicleAmount);
        rvp.setDamageSafeAmount(damageSafeAmount);
        rvp.setModelAmount(vehicleOrderItem.getUnitPrice());
        rvp.setVehicleHourNum(vehicleHourNum);

        rvp.setFreeHourNum(0);
        rvp.setFreeDayNum(0);
        rvp.setCutDayNum(offsetNum);
        rvp.setFreeAmount(vehicleOrderItem.getCutAmount());
        rvp.setBuyVehicleAmount(vehicleOrderItem.getBuyAmount());
        rvp.setRealVehicleAmount(vehicleOrderItem.getRealAmount());
        rvp.setCouponDesc(couponDesc);
        rvp.setUseAmountList(vehicleOrderItem.getVehicleDetail());
        rvp.setSameUnitPrice(vehicleOrderItem.getSameUnitPrice());

        rvp.initParamJson();
        //设置收费明细
        costDetail(rvp, handleChildren(detail));
        return rvp;
    }

    /**
     * 获取会员比例或者会员价
     * @param vehicleModel
     * @param prices
     * @param memberEnum
     * @return
     */
    private HandleDiscountDTO handleDiscount(AppUserDTO dto, VehicleModel vehicleModel, String[] prices, MemberEnum memberEnum) {
        BigDecimal modelAmount;//会员比例
        BigDecimal hundred = BigDecimal.TEN;
        Integer rebate = new Integer(0);
        if(DISCOUNT_STATUS_MEMBER.equals(vehicleModel.getRentDiscountStatus())) {
            rebate = dto.getDiscount();
            BigDecimal rebatePercent = new BigDecimal(String.valueOf((rebate/100d)));
            modelAmount = rebatePercent.multiply(vehicleModel.getPrice()).setScale(2, BigDecimal.ROUND_HALF_UP);
        }else {
            //会员固定价列表
            modelAmount = new BigDecimal(prices[(memberEnum.getCode() - 1)]);
            rebate = modelAmount.divide(vehicleModel.getPrice(), 2, BigDecimal.ROUND_UP).multiply(hundred).intValue();
        }
        HandleDiscountDTO handleDiscountDTO = new HandleDiscountDTO();
        handleDiscountDTO.setRebate(rebate);
        handleDiscountDTO.setModelAmount(modelAmount);
        return handleDiscountDTO;
    }

    @Data
    public class HandleDiscountDTO {
        BigDecimal modelAmount;
        Integer rebate;
    }

    private String handleChildren(RentVehicleBO detail) {
        StringBuffer childrenStr = new StringBuffer("");
//        if(vehicleDayNum > 0) {
            childrenStr.append(",${tem_0101}");
//        }
        if(DRIVER_TYPE_COMPANY.equals(detail.getDriverType())) {
            childrenStr.append(",${tem_0102}");
        }
        childrenStr.append(",${tem_0103}");
        if(DRIVER_TYPE_DAMAGE_SAFE.equals(detail.getDamageSafe())) {
            childrenStr.append(",${tem_0104}");
        }
        if(null != detail.getFreeDays() && detail.getFreeDays() > 0) {
            childrenStr.append(",${tem_0105}");
        }
        if(StrUtil.isNotBlank(detail.getOrder().getCouponTickerNos())) {
            childrenStr.append(",${tem_9901}");
        }
        if(childrenStr.length() > 0){
            childrenStr.deleteCharAt(0);
        }
        return childrenStr.toString();
    }

    /**
     * 计算费用明细
     * @param vo
     * @return
     */
    private void costDetail(RentVehiclePriceVO vo, String children) {
        OrderTemplate template = orderTemplateBiz.selectByCode(OrderCostEnum.RENT_VEHICLE.getCode());
        template.setTemplate(orderTemplateBiz.result(template.getTemplate()
                , CollUtil.zip(CollUtil.newArrayList("children", "vehicleAmount", "realAmount", "paramJson")
                                , CollUtil.newArrayList(children, vo.getVehicleAmount(), vo.getRealAmount(), ""))));
        String result = orderTemplateBiz.result(template, Dict.parse(vo));
        JSONObject jsonObject = JSONUtil.parseObj(result);
        jsonObject.put("paramJson", vo.getParamJson());
        result = JSONUtil.toJsonStr(jsonObject);
        vo.setCostDetail(result);
    }

    public void acquireVehicle(RentVehicleBO detail, String numberPlate, Integer status) {
        //根据车型、时间、距离，门店，预定车辆
        RentVehicleBookDTO rentVehicleBookDTO = BeanUtil.toBean(detail.getBookVehicleVO(), RentVehicleBookDTO.class);
        rentVehicleBookDTO.setModelId(detail.getModelId());
        rentVehicleBookDTO.setLiftCompany(detail.getStartCompanyId());
        rentVehicleBookDTO.setLiftAddr(detail.getStartAddr());
        rentVehicleBookDTO.setRetCompany(detail.getEndCompanyId());
        rentVehicleBookDTO.setStartCompanyId(detail.getStartCompanyId());
        rentVehicleBookDTO.setEndCompanyId(detail.getEndCompanyId());
        rentVehicleBookDTO.setOrderNo(detail.getOrder().getNo());
        rentVehicleBookDTO.setNumberPlate(numberPlate);
        rentVehicleBookDTO.setStatus(status);
        rentVehicleBookDTO.setUseType(detail.getUseType());
        rentVehicleBookDTO.setVehicleId(detail.getVehicleId());
        if (detail.getRentFreeDay() > 0) {//使用了免费天数
            rentVehicleBookDTO.setMemberUse(detail.getAppUserDTO().getMemberType());
        }

        if (detail.getAppUserDTO() != null) {
            rentVehicleBookDTO.setVehicleUserPhone(detail.getAppUserDTO().getUsername());
            rentVehicleBookDTO.setVehicleUsername(detail.getAppUserDTO().getRealname());
        }

        if(null != detail.getAccompanyItems()) {
            rentVehicleBookDTO.setSelectedAccItem(detail.getAccompanyItems().parallelStream().collect(Collectors.toMap(OrderAccompanyDTO::getId, OrderAccompanyDTO::getNum)));
        }
        ObjectRestResponse<VehicleBookRecord> orr = vehicleFeign.rentApplyVehicle(rentVehicleBookDTO);
        if(!CommonConstants.SYS_JSON_TRUE.equals(orr.getStatus())) {
            throw new BaseException(orr.getMessage(), orr.getStatus());
        }
        detail.setVehicleId(orr.getData().getVehicleId());
        //获取车辆信息 设置订单的goodsType
        Vehicle vehicle = vehicleFeign.get(orr.getData().getVehicleId()).getData();
        detail.getOrder().setGoodsType(vehicle.getGoodsType());
        detail.setBookRecordId(orr.getData().getId());
    }

}
