package com.xxfc.platform.order.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.StrUtil;
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.context.BaseContextHandler;
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.OrderCostDetailBiz;
import com.xxfc.platform.order.biz.OrderItemBiz;
import com.xxfc.platform.order.biz.OrderRentVehicleBiz;
import com.xxfc.platform.order.biz.OrderTemplateBiz;
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.OrderItem;
import com.xxfc.platform.order.entity.OrderTemplate;
import com.xxfc.platform.order.pojo.OrderAccompanyDTO;
import com.xxfc.platform.order.pojo.order.OrderItemDTO;
import com.xxfc.platform.order.pojo.order.RentVehicleBO;
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.constant.AccompanyingItemType;
import com.xxfc.platform.vehicle.entity.AccompanyingItem;
import com.xxfc.platform.vehicle.entity.BranchCompany;
import com.xxfc.platform.vehicle.entity.VehicleBookRecord;
import com.xxfc.platform.vehicle.entity.VehicleModel;
import com.xxfc.platform.vehicle.feign.VehicleFeign;
import com.xxfc.platform.vehicle.pojo.CompanyDetail;
import com.xxfc.platform.vehicle.pojo.RentVehicleBookDTO;
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.*;
import java.util.stream.Collectors;

import static com.github.wxiaoqi.security.admin.constant.enumerate.MemberEnum.*;
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.*;
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;

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


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

    public void initDetailSecond(RentVehicleBO bo) {
        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());
                    }
                }
            }
        }
    }

    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(bo.getVehicleModel().getPicture());
        //设置订单名称
        bo.getOrder().setName(bo.getVehicleModel().getName());

        //是否有使用会员权益 则调用接口触发新增消费记录次数
            //扣减免费天数
        if(SYS_TRUE.equals(bo.getOrder().getHasMemberRight())) {
            if(null == bo.getFreeDays()) {
                bo.setFreeDays(0);
            }
            int result = userFeign.memberDays(bo.getAppUserDTO().getUserid(), bo.getFreeDays(), UserFeign.MEMBER_DAYS_LOCK);
            if(result < 0) {
                throw new BaseException(ResultCode.FAILED_CODE);
            }
        }

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

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

        //插入随声物品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);

        //获取可用车辆
        acquireVehicle(bo, null, null);

        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);

        super.handleDetail(bo);

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

    @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) {
        BigDecimal realAmount = BigDecimal.ZERO;
        BigDecimal orderAmount = BigDecimal.ZERO;
        BigDecimal goodsAmount = BigDecimal.ZERO;
        BigDecimal vehicleAmount = BigDecimal.ZERO;
        BigDecimal driverAmount = BigDecimal.ZERO;
        BigDecimal damageSafeAmount = BigDecimal.ZERO;
//        BigDecimal modelAmount = BigDecimal.ZERO;
        BigDecimal couponAmount = BigDecimal.ZERO;
        Integer vehicleDayNum = 0;
        Integer freeDayNum = 0;

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

        //车型信息
        VehicleModel vehicleModel = vehicleFeign.get(detail.getModelId()).getData();

        //设置Item
        OrderItem vehicleOrderItem = orderItemBiz.initOrderItem(vehicleModel.getPrice(), detail.getDayNum(), vehicleModel.getName(), vehicleModel.getId(), ItemTypeEnum.VEHICLE_MODEL);
        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");
                }});
            }
            if(detail.getDayNum() > dto.getRentFreeDays()) {
                freeDayNum = dto.getRentFreeDays();
            }else {
                freeDayNum = detail.getDayNum();
            }
            vehicleOrderItem.setCutNum(freeDayNum);
            vehicleDayNum = detail.getDayNum() - freeDayNum;
            detail.getOrder().setHasMemberRight(SYS_TRUE);
        }else {
            vehicleDayNum = detail.getDayNum();
        }

        detail.setFreeDays(freeDayNum);

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

        //如果用户存在，并且为会员，并且车辆有优惠价
        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(",");
            HandleDiscountDTO handleDiscountDTO = new HandleDiscountDTO();
            switch (MemberEnum.getByCode(dto.getMemberLevel())) {
                case NORMAL:
                    handleDiscountDTO = handleDiscount(dto, vehicleModel, prices, NORMAL);
                    detail.getOrder().setHasMemberRight(SYS_TRUE);
                break;
                case GOLD:
                    handleDiscountDTO = handleDiscount(dto, vehicleModel, prices, GOLD);
                    detail.getOrder().setHasMemberRight(SYS_TRUE);
                    break;
                case DIAMOND:
                    handleDiscountDTO = handleDiscount(dto, vehicleModel, prices, DIAMOND);
                    detail.getOrder().setHasMemberRight(SYS_TRUE);
                    break;
            }
            detail.setRebate(handleDiscountDTO.getRebate());
            vehicleOrderItem.setUnitPrice(handleDiscountDTO.getModelAmount());
        }

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

        //单价 * （购买天数 - 减免天数）
        vehicleAmount = vehicleAmount.add(vehicleOrderItem.getCalculateAmount(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);
        }

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

        //vehicleAmount 优惠券处理
        if(null != detail.getTickerNo() && detail.getTickerNo().size() > 0) {
            couponAmount = activityFeign.use(dto.getUserid(), detail.getTickerNo(), detail.getOrder().getNo(), channel, vehicleAmount, ActivityFeign.TYPE_NO_USE);
            if(couponAmount.compareTo(BigDecimal.ZERO) > 0) {
                detail.getOrder().setCouponTickerNos(detail.getTickerNo().stream().collect(Collectors.joining(",")));
                detail.getOrder().setHasDiscount(SYS_TRUE);
                vehicleOrderItem.handleCouponAmount(couponAmount);
            }
        }

            //总价格（包含押金）
        orderAmount = orderAmount.add(goodsAmount).add(vehicleModel.getDeposit());
        realAmount = orderAmount.subtract(couponAmount);

        //生成订单明细
        RentVehiclePriceVO rvp = new RentVehiclePriceVO();
        rvp.setDeposit(vehicleModel.getDeposit());
        rvp.setDriverPrice(DRIVER_PRICE);
        rvp.setDamageSafePrice(DAMAGE_SAFE);
        rvp.setModelName(vehicleModel.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);

        //设置收费明细
        costDetail(rvp, handleChildren(detail, vehicleDayNum));
        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, Integer vehicleDayNum) {
        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(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.selectById(OrderCostEnum.RentVehicle.getCode());
        template.setTemplate(orderTemplateBiz.result(template.getTemplate(), new HashMap(){{
            put("children", children);
        }}));
        String result = orderTemplateBiz.result(template, Dict.parse(vo));
        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.setUserName(BaseContextHandler.getName());
        rentVehicleBookDTO.setLiftCompany(detail.getStartCompanyId());
        rentVehicleBookDTO.setLiftAddr(detail.getStartAddr());
        rentVehicleBookDTO.setRetCompany(detail.getEndCompanyId());
        rentVehicleBookDTO.setOrderNo(detail.getOrder().getNo());
        rentVehicleBookDTO.setNumberPlate(numberPlate);
        rentVehicleBookDTO.setStatus(status);
        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());
        detail.setBookRecordId(orr.getData().getId());
    }
}
