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.feign.dto.AppUserDTO;
import com.github.wxiaoqi.security.auth.client.config.UserAuthConfig;
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.OrderTemplateBiz;
import com.xxfc.platform.order.biz.OrderTourDetailBiz;
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.order.TourBO;
import com.xxfc.platform.order.pojo.price.TourPriceVO;
import com.xxfc.platform.tour.dto.TourSpePriceDTO;
import com.xxfc.platform.tour.entity.TourGood;
import com.xxfc.platform.tour.entity.TourGoodVerification;
import com.xxfc.platform.tour.entity.TourUser;
import com.xxfc.platform.tour.feign.TourFeign;
import com.xxfc.platform.tour.vo.TourSpePriceVo;
import com.xxfc.platform.universal.constant.DictionaryKey;
import com.xxfc.platform.universal.feign.ThirdFeign;
import com.xxfc.platform.vehicle.entity.SysRegion;
import com.xxfc.platform.vehicle.feign.VehicleFeign;
import com.xxfc.platform.vehicle.pojo.CompanyDetail;
import lombok.extern.log4j.Log4j;
import org.mockito.internal.util.collections.Sets;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.stream.Collectors;

import static com.github.wxiaoqi.security.common.constant.CommonConstants.*;
import static com.xxfc.platform.universal.constant.DictionaryKey.APP_ORDER;

@Service
@Log4j
public class OrderTourService extends AbstractOrderHandle<OrderTourDetailBiz, TourBO> {

    @Autowired
    TourFeign tourFeign;

    @Autowired
    VehicleFeign vehicleFeign;
    private static Integer IS_CHILD = 1;

    private static Integer LEVEL_DEFAULT = 0;
    private static Integer NUMBER_ZERO = 0;
    private static BigDecimal INSURE_PRICE;
    private static Long autoCancelTime;
            //= new BigDecimal("5.00"); //保险

    @Autowired
    OrderCostDetailBiz orderCostDetailBiz;

    @Autowired
    OrderTemplateBiz orderTemplateBiz;

    @Autowired
    protected UserAuthConfig userAuthConfig;

    @Autowired
    ThirdFeign thirdFeign;

    @Autowired
    ActivityFeign activityFeign;

    @Autowired
    public HttpServletRequest request;

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

    public AppUserDTO getUserInfo(){
        return  userFeign.userDetailByToken(userAuthConfig.getToken(request)).getData();
    }

    @Override
    public void initDetail(TourBO bo) {
        super.initDetail(bo);
        initDictionary();
        TourGood tourGood = tourFeign.usableGet(bo.getGoodId()).getData();
        bo.setTourGood(tourGood);
        bo.setAppUserDTO(getUserInfo());
    }

    public void initDictionary() {
        dictionaryMap = thirdFeign.dictionaryGetAll4Map().getData();
        this.INSURE_PRICE = new BigDecimal(dictionaryMap.get(APP_ORDER+ "_"+ DictionaryKey.INSURE_PRICE).getDetail());
        this.autoCancelTime = Long.valueOf(dictionaryMap.get(APP_ORDER+ "_"+ DictionaryKey.ACT_TOUR).getDetail());
    }

    @Override
    public void handleDetail(TourBO bo) {
        //设置订单状态为3
        bo.getOrder().setStatus(OrderStatusEnum.ORDER_UNPAY.getCode());
        //设置订单图片
        bo.getOrder().setPicture(bo.getTourGood().getCover());
        //设置订单名称
        bo.getOrder().setName(bo.getTourGood().getName());

        //设置城市
        CompanyDetail companyDetail = vehicleFeign.getCompanyDetail(bo.getStartCompanyId()).getData();
        SysRegion sysRegion = companyDetail.getSysRegions().get(1);
        bo.setStartCity(sysRegion.getId().intValue());
        bo.setStartCityName(sysRegion.getName());

        //设置省内，省外
        bo.setIsOutside(bo.getTourGood().getIsOutside());

        //设置verificationId 核销id
        bo.setVerificationId(tourFeign.entityList(BeanUtil.beanToMap(new TourGoodVerification(){{
            setSpeId(bo.getSpePriceId());
            setGoodId(bo.getGoodId());
            setSiteId(bo.getSiteId());
        }})).getData().get(0).getId());

        Integer departureStatus = tourFeign.selectDepartureStatusByVerificationId(bo.getVerificationId());
        //1为已发车
        if(!SYS_FALSE.equals(departureStatus)) {
            throw new BaseException(ResultCode.PARAM_EPIRE_CODE, Sets.newSet("旅程已发车，不能下单"));
        }

        //扣減庫存
        ObjectRestResponse<TourSpePriceVo> response = tourFeign.stock(bo.getSpePriceId(), bo.getTotalNumber(), TourFeign.STOCK_SUBTRACT);
        if(!SYS_JSON_TRUE.equals(response.getStatus())) {
            throw new BaseException(ResultCode.PARAM_EPIRE_CODE, Sets.newSet(response.getMessage()));
        }


        OrderItem tourAdultItem = bo.getItemByTypeEnum(ItemTypeEnum.TOUR_ADULT);
        OrderItem tourChildItem = bo.getItemByTypeEnum(ItemTypeEnum.TOUR_CHILD);
        BigDecimal amount = tourAdultItem.getTotalAmount().add(null == tourChildItem? BigDecimal.ZERO: tourChildItem.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);
        }

        super.handleDetail(bo);

        //发送定时取消订单(30分钟)
        rabbitProduct.sendDelayMessage(bo.getOrder(), autoCancelTime);
    }

    @Override
    public void handleCalculate(TourBO bo) {
        TourPriceVO tpv = calculatePrice(bo);
        BeanUtil.copyProperties(tpv, bo.getOrder());
        BeanUtil.copyProperties(tpv, bo);
    }

    @Override
    public TourPriceVO calculatePrice(TourBO detail) {
        BigDecimal realAmount = BigDecimal.ZERO;
        BigDecimal orderAmount = BigDecimal.ZERO;
        BigDecimal goodsAmount = BigDecimal.ZERO;
        BigDecimal tourAmount = BigDecimal.ZERO;
        BigDecimal couponAmount = BigDecimal.ZERO;
        String couponDesc = "";
        BigDecimal insureAmount = BigDecimal.ZERO;

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

        if(StrUtil.isNotBlank(detail.getTourUserIds())) {
            List<TourUser> users = new ArrayList<TourUser>();
            if(StrUtil.isNotBlank(detail.getTourUserIds())) {
                users = tourFeign.getTourUsers(detail.getTourUserIds()).getData();
            }

            List<TourUser> notChilds = users.parallelStream().filter(tourUser ->{
                return !IS_CHILD.equals(tourUser.getIsChild());
            }).collect(Collectors.toList());

            List<TourUser> childs = users.parallelStream().filter(tourUser ->{
                return IS_CHILD.equals(tourUser.getIsChild());
            }).collect(Collectors.toList());

            detail.setAdultNum(notChilds.size());
            detail.setChildNum(childs.size());
            detail.setTotalNumber(users.size());
        }else{
            detail.setTotalNumber(detail.getAdultNum() + detail.getChildNum());
        }

        if(detail.getAdultNum() <= 0) {
            throw new BaseException(ResultCode.PARAM_ILLEGAL_CODE, new HashSet<String>(){{add("最少一个成人");}});
        }

        //计算旅游价格
        ObjectRestResponse<TourSpePriceVo> objectRestResponse = tourFeign.refund(new TourSpePriceDTO(){{
            setChildNumber(detail.getChildNum());
            setNumber(detail.getAdultNum());
            setLevel(LEVEL_DEFAULT);
            setSpeId(detail.getSpePriceId());
            setUserId(detail.getAppUserDTO().getUserid());
        }});
        TourSpePriceVo tourSpePriceVo = objectRestResponse.getData();

        //设置Item
        OrderItem tourAdultItem = orderItemBiz.initOrderItem(tourSpePriceVo.getOriginalPrice(), detail.getAdultNum(), "成人", detail.getSpePriceId().toString(), ItemTypeEnum.TOUR_ADULT);
        tourAdultItem.setUnitPrice(tourSpePriceVo.getPrice());
        OrderItem tourChildItem = orderItemBiz.initOrderItem(tourSpePriceVo.getChildOriginalPrice(), detail.getChildNum(), "儿童", detail.getSpePriceId().toString(), ItemTypeEnum.TOUR_CHILD);
        tourChildItem.setUnitPrice(tourSpePriceVo.getChildPrice());

        //人数 * 天数
        OrderItem insureItem = orderItemBiz.initOrderItem(INSURE_PRICE, detail.getTotalNumber() * detail.getTourGood().getNumber(), "旅游保险", null, ItemTypeEnum.TOUR_INSURE);

        detail.setItems(new ArrayList<OrderItem>());
        detail.getItems().add(tourAdultItem);
        if(tourChildItem.getBuyNum() > 0) {
            detail.getItems().add(tourChildItem);
        }


        //需要保险
        if(SYS_TRUE.equals(detail.getHasInsure())) {
            //人数 * 天数 * 价格
            insureAmount = insureAmount.add(insureItem.getCalculateAmount(Boolean.TRUE));
            detail.getItems().add(insureItem);
        }

            //总价
        tourAmount = tourAmount.add(tourAdultItem.getCalculateAmount(Boolean.TRUE)).add(tourChildItem.getCalculateAmount(Boolean.TRUE));
            //商品价格
        goodsAmount = goodsAmount.add(tourAmount).add(insureAmount);

        //优惠券处理
        //待完成
        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, tourAmount, 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);
                BigDecimal residueCouponAmount = tourAdultItem.handleCouponAmount(couponAmount);
                if(residueCouponAmount.compareTo(BigDecimal.ZERO) > 0) {
                    tourChildItem.handleCouponAmount(residueCouponAmount);
                }
            }
        }

            //总价格
        orderAmount = orderAmount.add(goodsAmount);


            //真实价格
        realAmount = realAmount.add(orderAmount).subtract(couponAmount);

            //生成订单明细
        TourPriceVO tpv = BeanUtil.toBean(tourSpePriceVo, TourPriceVO.class);
        tpv.setCouponAmount(couponAmount);
        tpv.setCouponDesc(couponDesc);
        tpv.setOrderAmount(orderAmount);
        tpv.setGoodsAmount(goodsAmount);
        tpv.setRealAmount(realAmount);
        tpv.setNumber(detail.getAdultNum());
        tpv.setChildNumber(detail.getChildNum());
        tpv.setInsurePrice(INSURE_PRICE);
        tpv.setDayNum(detail.getTourGood().getNumber());
        tpv.setInsureAmount(insureAmount);
        tpv.setTotalNumber(detail.getTotalNumber());

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

    private String handleChildren(TourBO detail) {
        StringBuffer childrenStr = new StringBuffer("");
        if(NUMBER_ZERO < detail.getAdultNum()) {
            childrenStr.append(",${tem_0201}");
        }
        if(NUMBER_ZERO < detail.getChildNum()) {
            childrenStr.append(",${tem_0202}");
        }
        if(SYS_TRUE.equals(detail.getHasInsure())) {
            childrenStr.append(",${tem_0203}");
        }
        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(TourPriceVO vo, String children) {
        OrderTemplate template = orderTemplateBiz.selectByCode(OrderCostEnum.TOUR.getCode());
        template.setTemplate(orderTemplateBiz.result(template.getTemplate(), new HashMap(){{
            put("children", children);
            put("paramJson", "");
        }}));
        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);
    }
}
