package com.xxfc.platform.order.rest;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.github.wxiaoqi.security.admin.feign.UserFeign;
import com.github.wxiaoqi.security.admin.feign.dto.UserDTO;
import com.github.wxiaoqi.security.admin.feign.rest.UserRestInterface;
import com.github.wxiaoqi.security.auth.client.annotation.IgnoreClientToken;
import com.github.wxiaoqi.security.auth.client.annotation.IgnoreUserToken;
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.rest.CommonBaseController;
import com.github.wxiaoqi.security.common.util.ClientUtil;
import com.github.wxiaoqi.security.common.util.Query;
import com.github.wxiaoqi.security.common.util.process.ResultCode;
import com.github.wxiaoqi.security.common.vo.PageDataVO;
import com.xxfc.platform.order.biz.*;
import com.xxfc.platform.order.biz.inner.OrderCancelBiz;
import com.xxfc.platform.order.biz.inner.OrderMsgBiz;
import com.xxfc.platform.order.contant.enumerate.CrosstownTypeEnum;
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.mqhandler.RabbitProduct;
import com.xxfc.platform.order.pojo.dto.OrderDTO;
import com.xxfc.platform.order.pojo.mq.OrderMQDTO;
import com.xxfc.platform.order.pojo.order.CancelOrderDTO;
import com.xxfc.platform.order.pojo.order.OrderAboutParamDTO;
import com.xxfc.platform.order.pojo.order.OrderPageVO;
import com.xxfc.platform.order.pojo.order.QueryOrderDTO;
import com.xxfc.platform.order.pojo.pay.NotifyUrlDTO;
import com.xxfc.platform.order.pojo.pay.OrderPayDTO;
import com.xxfc.platform.universal.constant.DictionaryKey;
import com.xxfc.platform.universal.entity.Dictionary;
import com.xxfc.platform.universal.feign.ThirdFeign;
import com.xxfc.platform.universal.vo.OrderPayVo;
import com.xxfc.platform.universal.vo.OrderRefundVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.annotations.ApiOperation;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import tk.mybatis.mapper.entity.Example;
import tk.mybatis.mapper.weekend.WeekendSqls;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

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

@Controller
@RequestMapping("baseOrder")
@Api(value = "订单", tags = {"订单"})
@Slf4j
public class BaseOrderController extends CommonBaseController implements UserRestInterface {

    public static final Integer STATUS_SUCCESS = 1;
    @Autowired
    BaseOrderBiz baseOrderBiz;

    @Autowired
    OrderMemberDetailBiz orderMemberDetailBiz;

    @Autowired
    OrderUserLicenseBiz orderUserLicenseBiz;

    @Autowired
    OrderCancelBiz orderCancelBiz;

    @Autowired
    ThirdFeign thirdFeign;

    @Autowired
    UserFeign userFeign;

    @Autowired
    RabbitProduct rabbitProduct;

    @Autowired
    OrderItemBiz orderItemBiz;

    @Autowired
    OrderRentVehicleBiz orderRentVehicleBiz;

    @Autowired
    OrderVehicleCrosstownBiz crosstownBiz;

    @Autowired
    OrderViolationBiz orderViolationBiz;

    @Autowired
    OrderAccountBiz orderAccountBiz;

    @Autowired
    OrderMsgBiz orderMsgBiz;

    @Autowired
    OrderDepositRefundRecordBiz orderDepositRefundRecordBiz;

    @Override
    public UserFeign getUserFeign() {
        return userFeign;
    }

    @Value("${gateway.insideHost}")
    String insideHost;

    @Value("${gateway.host}")
    String host;

    @Value("${gateway.order}")
    String order;


    String qrcodePrefix = "fcwx://order";
    String notifyUrl = "/baseOrder/app/unauth/notifyUrl";

    @RequestMapping(value = "/app/unauth/getOrderUnitPrice", method = RequestMethod.GET)
    @ResponseBody
    @ApiOperation(value = "获取订单相关的单价")
    @IgnoreClientToken
    @IgnoreUserToken
    public ObjectRestResponse<OrderAboutParamDTO> getOrderUnitPrice() {
        Map<String, Dictionary> dictionaryMap = thirdFeign.dictionaryGetAll4Map().getData();
        return ObjectRestResponse.succ(new OrderAboutParamDTO() {{
            setInsurePrice(new BigDecimal(dictionaryMap.get(APP_ORDER + "_" + DictionaryKey.INSURE_PRICE).getDetail()));
        }});
    }

    @RequestMapping(value = "/app/unauth/getOrderParam", method = RequestMethod.GET)
    @ResponseBody
    @ApiOperation(value = "获取订单相关的参数")
    @IgnoreClientToken
    @IgnoreUserToken
    public ObjectRestResponse<OrderAboutParamDTO> getOrderParam() {
        Map<String, Dictionary> dictionaryMap = thirdFeign.dictionaryGetAll4Map().getData();
        return ObjectRestResponse.succ(new OrderAboutParamDTO() {{
            setInsurePrice(new BigDecimal(dictionaryMap.get(APP_ORDER + "_" + DictionaryKey.INSURE_PRICE).getDetail()));
            setActRent(new Long(dictionaryMap.get(APP_ORDER + "_" + DictionaryKey.ACT_RENT).getDetail()));
            setActTour(new Long(dictionaryMap.get(APP_ORDER + "_" + DictionaryKey.ACT_TOUR).getDetail()));
            setActMember(new Long(dictionaryMap.get(APP_ORDER + "_" + DictionaryKey.ACT_MEMBER).getDetail()));
            setDamageSafe(new BigDecimal(dictionaryMap.get(APP_ORDER + "_" + DictionaryKey.DAMAGE_SAFE).getDetail()));
            setDriverPrice(new BigDecimal(dictionaryMap.get(APP_ORDER + "_" + DictionaryKey.DRIVER_PRICE).getDetail()));
        }});
    }


    @RequestMapping(value = "/page", method = RequestMethod.GET)
    @ResponseBody
    @ApiOperation(value = "订单列表")
    @IgnoreClientToken
    public ObjectRestResponse<PageDataVO<OrderPageVO>> list(QueryOrderDTO dto) {
        //查询列表数据
        if (StringUtils.isBlank(BaseContextHandler.getUserID())) {
            throw new BaseException(ResultCode.AJAX_WECHAT_NOTEXIST_CODE);
        }
        //dto.setCrtUser(Integer.valueOf(BaseContextHandler.getUserID()));
        dto.setUserId(Integer.valueOf(BaseContextHandler.getUserID()));
        Query query = new Query(dto);
        PageDataVO<OrderPageVO> pages = PageDataVO.pageInfo(query, () -> baseOrderBiz.pageByParm(query.getSuper()));
        pages.getData().parallelStream().forEach(data -> {
            data.setQrcodeStr(qrcodePrefix);
//            data.setOrderRealAmount(data.getRealAmount().subtract(orderAccountBiz.getAllOrderCost(data.getId())));
//        	log.info("订单实际支付金额，扣除押金违章之后: {}", data.getOrderRealAmount());
        });
        return new ObjectRestResponse<>().data(pages);
    }

    @RequestMapping(value = "/getInvoiceOrderList", method = RequestMethod.GET)
    @ResponseBody
    @ApiOperation(value = "发票订单列表")
    @IgnoreClientToken
    public ObjectRestResponse<PageDataVO<OrderPageVO>> getInvoiceOrderList(QueryOrderDTO dto) {
        //查询列表数据
        if (StringUtils.isBlank(BaseContextHandler.getUserID())) {
            throw new BaseException(ResultCode.AJAX_WECHAT_NOTEXIST_CODE);
        }
        //dto.setCrtUser(Integer.valueOf(BaseContextHandler.getUserID()));
        dto.setUserId(Integer.valueOf(BaseContextHandler.getUserID()));
        if (dto.getType() == OrderTypeEnum.RENT_VEHICLE.getCode()) {
            dto.setRefundStatus(3);
        }
        if (StringUtils.isBlank(dto.getOrderIds())) {
            dto.setInvoiceStatus(0);
        } else {
            dto.setInvoiceStatus(1);
        }
        Query query = new Query(dto);
        PageDataVO<OrderPageVO> pages = PageDataVO.pageInfo(query, () -> baseOrderBiz.pageByParm(query.getSuper()));
        pages.getData().parallelStream().forEach(data -> {
            data.setQrcodeStr(qrcodePrefix);

            BigDecimal bigDecimal = new BigDecimal(data.getRealAmount().doubleValue()-orderAccountBiz.getAllOrderCost(data.getId())).setScale(2,BigDecimal.ROUND_HALF_UP);
            data.setOrderRealAmount(bigDecimal);
            log.info("订单实际支付金额，扣除押金违章之后: {}", data.getOrderRealAmount());
        });
        return new ObjectRestResponse<>().data(pages);
    }
    @ApiOperation("查询个数")
    @RequestMapping(value = "/count",method = RequestMethod.GET)
    @ResponseBody
    @IgnoreUserToken
    public ObjectRestResponse<Integer> entityList(Integer hasMemberRight, String multiStatus, String multiTypes, Integer userId){
        //查询列表数据
        WeekendSqls<BaseOrder> weekendSqls = WeekendSqls.<BaseOrder>custom();
        if(null != hasMemberRight) {
            weekendSqls.andEqualTo(BaseOrder::getHasMemberRight, hasMemberRight);
        }
        if(null != multiStatus) {
            weekendSqls.andIn(BaseOrder::getStatus,
                    StrUtil.splitTrim(multiStatus, ",")
                            .parallelStream().map(v -> Integer.valueOf(v)).collect(Collectors.toList()));
        }
        if(null != multiTypes) {
            weekendSqls.andIn(BaseOrder::getType,
                    StrUtil.splitTrim(multiTypes, ",")
                            .parallelStream().map(v -> Integer.valueOf(v)).collect(Collectors.toList()));
        }
        if(null != userId) {
            weekendSqls.andEqualTo(BaseOrder::getUserId, userId);
        }
//                null;
        return ObjectRestResponse.succ(baseOrderBiz
                .selectCountByExample( new Example.Builder(BaseOrder.class)
                        .where(weekendSqls).build()));
    }

    @ApiOperation("订单详情")
    @RequestMapping(value = "/{no}", method = RequestMethod.GET)
    @IgnoreClientToken
    @ResponseBody
    public ObjectRestResponse<OrderPageVO> get(@PathVariable String no) {
        log.info("no:" + no + ",时间戳：" + System.currentTimeMillis());
        checkAppUser();

        //查询列表数据
        Query query = baseOrderBiz.initQuery(no);
        PageDataVO<OrderPageVO> page = PageDataVO.pageInfo(query, () -> baseOrderBiz.pageByParm(query.getSuper()));
        if (page.getData().isEmpty()) {
            throw new BaseException(ResultCode.NOTEXIST_CODE);
        }
        log.info("no:" + no + ",时间戳：" + System.currentTimeMillis());
        OrderPageVO orderPageVO = page.getData().get(0);
        orderPageVO.setQrcodeStr(qrcodePrefix);
        orderPageVO.setItems(orderItemBiz.selectList(new OrderItem(){{
            setOrderId(orderPageVO.getId());
        }}));
        return new ObjectRestResponse<>().data(page.getData().get(0));
    }

    @RequestMapping(value = "/pay", method = RequestMethod.POST)
    @ResponseBody
    @ApiOperation(value = "订单支付")
    @IgnoreClientToken
    public ObjectRestResponse pay(@RequestBody OrderPayDTO dto) {
        //查询列表数据
        if (StringUtils.isBlank(BaseContextHandler.getUserID())) {
            throw new BaseException(ResultCode.AJAX_WECHAT_NOTEXIST_CODE);
        }

        OrderPayVo orderPayVo = BeanUtil.toBean(dto, OrderPayVo.class);

        BaseOrder baseOrder = baseOrderBiz.selectOne(new BaseOrder() {{
            setNo(dto.getOrderNo());
        }});

        if (null == baseOrder || !OrderStatusEnum.ORDER_UNPAY.getCode().equals(baseOrder.getStatus())) {
            throw new BaseException("订单不可支付", ResultCode.EXCEPTION_CODE);
        }

        orderPayVo.setAmount(baseOrder.getRealAmount().multiply(new BigDecimal("100")).intValue());
        orderPayVo.setBody(baseOrder.getName());
        orderPayVo.setBuyerIp(StringUtils.defaultIfBlank(request.getHeader("userHost"), ClientUtil.getClientIp(request)));
        orderPayVo.setChannel(baseOrder.getType());
        orderPayVo.setNotifyUrl(insideHost + order + notifyUrl + "?orderNo=" + baseOrder.getNo());
        orderPayVo.setSubject(baseOrder.getName());
        orderPayVo.setUserId(baseOrder.getUserId());
        ObjectRestResponse response = BeanUtil.toBean(thirdFeign.wx(orderPayVo), ObjectRestResponse.class);
        return response;
    }

    @RequestMapping(value = "/cancel/{no}", method = RequestMethod.POST)
    @ResponseBody
    @ApiOperation(value = "取消订单")
    @IgnoreClientToken
    public ObjectRestResponse cancel(@PathVariable String no, @RequestBody CancelOrderDTO cancelOrderDto) {
        //查询列表数据
        if (StringUtils.isBlank(BaseContextHandler.getUserID())) {
            throw new BaseException(ResultCode.AJAX_WECHAT_NOTEXIST_CODE);
        }
        cancelCommon(no, cancelOrderDto, BaseContextHandler.getUserID(), null);
        return ObjectRestResponse.succ();
    }

    @RequestMapping(value = "/back-stage/cancel/{no}", method = RequestMethod.POST)
    @ResponseBody
    @ApiOperation(value = "后台取消订单")
    @IgnoreClientToken
    public ObjectRestResponse bgCancel(@PathVariable String no, @RequestBody CancelOrderDTO cancelOrderDto) {
        //查询列表数据
        if (StringUtils.isBlank(cancelOrderDto.getAppUserId())) {
            throw new BaseException(ResultCode.AJAX_WECHAT_NOTEXIST_CODE);
        }
        cancelCommon(no, cancelOrderDto, cancelOrderDto.getAppUserId(), cancelOrderDto.getChangeViolateAmount());
        return ObjectRestResponse.succ();
    }

    private void cancelCommon(String no, CancelOrderDTO cancelOrderDto, String userId, BigDecimal changeViolateAmount) {
        BaseOrder dbBaseOrder = baseOrderBiz.selectOne(new BaseOrder() {{
            setNo(no);
        }});
        if (null == dbBaseOrder || !userId.equals(dbBaseOrder.getUserId().toString())) {
            throw new BaseException(ResultCode.NOTEXIST_CODE);
        }
        dbBaseOrder.setCancelReason(cancelOrderDto.getCancelReason());
        orderCancelBiz.cancel(dbBaseOrder, changeViolateAmount);
    }

    @RequestMapping(value = "/app/unauth/notifyUrl", method = RequestMethod.GET)
    @ResponseBody
    @ApiOperation(value = "订单支付回调")
    @IgnoreClientToken
    @IgnoreUserToken
    public ObjectRestResponse notifyUrl(NotifyUrlDTO dto) {
        //判断是否成功，并且订单是未支付状态，则添加支付编号和修改状态
        if (StrUtil.isNotBlank(dto.getOrderNo())) {
            baseOrderBiz.payNotifyHandle(dto.getOrderNo(), dto.getTradeNo(), dto.getType(), dto.getPayWay());
        } else {
            log.error(" exception notifyUrl : " + JSONUtil.toJsonStr(dto));
        }
        return ObjectRestResponse.succ();
    }

    @RequestMapping(value = "/app/unauth/send-msg", method = RequestMethod.GET)
    @ResponseBody
    @ApiOperation(value = "mq发送消息")
    @IgnoreClientToken
    @IgnoreUserToken
    public ObjectRestResponse sendMsg() {
        rabbitProduct.sendDelayMessage(baseOrderBiz.selectById(93), 1000L * 60);
        return ObjectRestResponse.succ();
    }

    public UserDTO getAdminUserInfo() {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        if (request.getHeader("Authorization") != null) {
            return userFeign.userinfoByToken(request.getHeader("Authorization")).getData();
        }
        return null;
    }

    @Data
    public class QueryOrderList extends BaseOrderBiz.QueryOrderDetailDTO {

        private Long startTime;

        private Long endTime;

        private Integer startCompanyId;

        private Integer startZoneId;

        private Integer zoneId;

        private Integer userId;

        private Integer type;

        private String phone;
        //违章押金退还状态
        private Integer refundStatus;

        /**
         * 后台搜索条件：真实姓名
         */
        private String realName;

        /**
         * 后台搜索条件：车辆编号
         */
        private String vehicleCode;

        private  List<String> vehicleIds;

        /**
         * 获取一条车辆详情,需要传的订单号
         */
        private String oneNo;

        private Integer status;
        //订单用户ID列表
        private List<Integer> userIds;
        //订单用户大区id列表
        private List<Integer> zoneIds;
        //订单用户手机号或订单用户真实姓名
        private String keywords;

        /**
         * 车牌号
         */
        private String plateNumber;

        @ApiModelProperty("当前页码")
        Integer page;
        @ApiModelProperty("每页限制")
        Integer limit;
        /**
         * 会员等级
         */
        Integer memberLevel;
        List<Integer> companyIds;

    }

    @RequestMapping(value = "/app/unauth/refund/{no}/{refundAmount}", method = RequestMethod.POST)
    @ResponseBody
    @ApiOperation(value = "退款")
    @IgnoreClientToken
    @IgnoreUserToken
    public ObjectRestResponse refundAmount(@PathVariable("no") String no, @PathVariable("refundAmount") BigDecimal refundAmount) {
        OrderRefundVo orv = new OrderRefundVo();
        BaseOrder baseOrder = baseOrderBiz.selectOne(new BaseOrder(){{
            setNo(no);
        }});
        orv.setAmount(baseOrder.getRealAmount().multiply(new BigDecimal("100")).intValue());
        orv.setOrderNo(baseOrder.getNo());
        orv.setRefundDesc("退款订单号："+ no);
        orv.setRefundAmount(refundAmount.multiply(new BigDecimal("100")).intValue());
        ObjectRestResponse<String> result = thirdFeign.refund(orv);
        return ObjectRestResponse.succ(result);
    }

    @RequestMapping(value = "/app/unauth/refundDeposit/{no}", method = RequestMethod.POST)
    @ResponseBody
    @ApiOperation(value = "退款违章保证金")
    @IgnoreClientToken
    @IgnoreUserToken
    public ObjectRestResponse refundDepositAmount(@PathVariable("no") String no) {
        if(StrUtil.isBlank(no)) {
            return ObjectRestResponse.createDefaultFail();
        }
        BaseOrder baseOrder = baseOrderBiz.selectOne(new BaseOrder(){{
            setNo(no);
        }});

        OrderRentVehicleDetail orvd = orderRentVehicleBiz.selectOne(new OrderRentVehicleDetail() {{
            setOrderId(baseOrder.getId());
        }});

        Integer crosstownTypeEnum;
        //判断是否定损过
        if(SYS_TRUE.equals(orvd.getFixedLossStatus())) {
            crosstownTypeEnum = CrosstownTypeEnum.FIXED_LOSS.getCode();
        }else {
            crosstownTypeEnum = CrosstownTypeEnum.ARRIVE.getCode();
        }
        OrderVehicleCrosstown crosstown = crosstownBiz.selectOne(new OrderVehicleCrosstown(){{
            setOrderId(baseOrder.getId());
            setType(crosstownTypeEnum);
        }});

        orderAccountBiz.handleRentDepositMargin(baseOrder, orvd, crosstown);

        return ObjectRestResponse.succ();
    }

    @RequestMapping(value = "/app/unauth/refundPartDeposit/{no}", method = RequestMethod.POST)
    @ResponseBody
    @ApiOperation(value = "退款第一部分证金")
    @IgnoreClientToken
    @IgnoreUserToken
    public ObjectRestResponse refundPartDepositAmount(@PathVariable("no") String no) {
        if(StrUtil.isBlank(no)) {
            return ObjectRestResponse.createDefaultFail();
        }
        BaseOrder baseOrder = baseOrderBiz.selectOne(new BaseOrder(){{
            setNo(no);
        }});
        //发送队列消息
        OrderMQDTO orderMQDTO = BeanUtil.toBean(baseOrder, OrderMQDTO.class);
        orderMQDTO.setOrderRentVehicleDetail(orderRentVehicleBiz.selectOne(new OrderRentVehicleDetail(){{
            setOrderId(baseOrder.getId());
        }}));
        orderMQDTO.setOrderTourDetail(new OrderTourDetail());
        orderMQDTO.setOrderMemberDetail(new OrderMemberDetail());

        //获取item
        orderMQDTO.setItems(orderItemBiz.selectList(new OrderItem() {{
            setOrderId(baseOrder.getId());
        }}));

        //租车订单完成
        if(OrderTypeEnum.RENT_VEHICLE.getCode().equals(orderMQDTO.getType())) {
            orderAccountBiz.refundPartDeposit(orderMQDTO);
        }

        return ObjectRestResponse.succ();
    }

    @RequestMapping(value = "/basebase/aaa", method = RequestMethod.GET)
    @IgnoreClientToken
    @IgnoreUserToken
    public ObjectRestResponse<List<OrderDTO>> findOrdersByorderId(@RequestParam(value = "orderIds") String orderIds){
        return ObjectRestResponse.succ();
                //ObjectRestResponse.succ(baseOrderBiz.selectBaeOrderByOrderIds(orderIds));
    }

    @RequestMapping(value = "/updateOrder", method = RequestMethod.POST)
    public ObjectRestResponse updateOrder(@RequestBody BaseOrder baseOrder) {
        return baseOrderBiz.updateBaseOrder(baseOrder);
    }

}
