package com.freemud.application.sdk.api.ordercenter.service;

import com.freemud.application.sdk.api.base.BaseRequest;
import com.freemud.application.sdk.api.log.ApiLog;
import com.freemud.application.sdk.api.log.ErrorLog;
import com.freemud.application.sdk.api.log.LogThreadLocal;
import com.freemud.application.sdk.api.log.ThirdPartyLog;
import com.freemud.application.sdk.api.ordercenter.config.OrderCenterProperties;
import com.freemud.application.sdk.api.ordercenter.config.OrderDownLoadCenterProperties;
import com.freemud.application.sdk.api.ordercenter.constant.InterfaceAddressConstant;
import com.freemud.application.sdk.api.ordercenter.enums.ResponseResultEnum;
import com.freemud.application.sdk.api.ordercenter.request.OrderConditionsReq;
import com.freemud.application.sdk.api.ordercenter.request.ParkingOrderConditionsReq;
import com.freemud.application.sdk.api.ordercenter.request.QueryAfterSalesOrderConditionsReq;
import com.freemud.application.sdk.api.ordercenter.request.QueryOrderByScrollRequest;
import com.freemud.application.sdk.api.ordercenter.request.create.BatchQueryByCodesReq;
import com.freemud.application.sdk.api.ordercenter.response.BaseDownLoadResponse;
import com.freemud.application.sdk.api.ordercenter.response.AfterSalesListResp;
import com.freemud.application.sdk.api.ordercenter.response.BaseResponse;
import com.freemud.application.sdk.api.ordercenter.response.OrderItemStatisticsResponse;
import com.freemud.application.sdk.api.ordercenter.response.orderInfo.AfterSalesOrderResp;
import com.freemud.application.sdk.api.ordercenter.response.orderInfo.OrderInfoReqs;
import com.freemud.application.sdk.api.ordercenter.response.orderInfo.OrderStatisticsResp;
import com.freemud.application.sdk.api.ordercenter.response.orderInfo.QueryByCodeResponse;
import com.freemud.application.sdk.api.ordercenter.util.LogUtil;
import com.freemud.application.sdk.api.util.RequestThirdPartyUtils;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.client.RestTemplate;

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

/**
 * All rights Reserved, Designed By www.freemud.com
 *
 * @version V1.0
 * @Title:
 * @Package: com.freemud.application.sdk.api.ordercenter.service
 * @Descripttion:
 * @author: shuhu.hou
 * @date: 2019/8/1
 * @Copyright: 2017 www.freemud.cn Inc. All rights reserved.
 * 注意：本内容仅限于上海非码科技内部传阅，禁止外泄以及用于其他的商业目.
 */
@Service
@Log4j2
public class OrderDownLoadSdkService {

    @Autowired
    @Qualifier("orderDownLoadRestTemplate")
    private RestTemplate restTemplate;
    @Autowired
    private OrderDownLoadCenterProperties orderCenterProperties;
    public static final String SUCCESS_RESPONSE_CODE = "100";
    @Autowired
    private OrderCenterProperties orderCenter;
    @Autowired
    private OrderSdkService orderSdkService;
    @Autowired
    private LogUtil logUtil;
    /**
     * 根据综合条件查询订单
     */
    public BaseDownLoadResponse<List<OrderInfoReqs>> queryOrderByConditions(OrderConditionsReq request, String trackingNo) {
        long begin = System.currentTimeMillis();
        BaseDownLoadResponse<List<OrderInfoReqs>> responseDTO = RequestThirdPartyUtils.httpJsonReqComplexDownLoad(restTemplate, InterfaceAddressConstant.QUERY_ORDER_BY_CONDITIONS,
                createBaseRequest(request, trackingNo), new ParameterizedTypeReference<BaseDownLoadResponse<List<OrderInfoReqs>>>() {
                });
        batchCheckTime(request,responseDTO);
        ThirdPartyLog.infoConvertJson(begin, System.currentTimeMillis(), InterfaceAddressConstant.QUERY_ORDER_BY_CONDITIONS, request, responseMini(responseDTO));
        return responseHandle(responseDTO);
    }

    public BaseDownLoadResponse<List<OrderInfoReqs>> queryOrderByScroll(QueryOrderByScrollRequest request, String trackingNo) {
        long begin = System.currentTimeMillis();
        BaseDownLoadResponse<List<OrderInfoReqs>> responseDTO = RequestThirdPartyUtils.httpJsonReqComplexDownLoad(restTemplate, InterfaceAddressConstant.QUERY_ORDER_BY_SCROLL,
                createBaseRequest(request, trackingNo), new ParameterizedTypeReference<BaseDownLoadResponse<List<OrderInfoReqs>>>() {
                });
        ThirdPartyLog.infoConvertJson(begin, System.currentTimeMillis(), InterfaceAddressConstant.QUERY_ORDER_BY_SCROLL, request, responseMini(responseDTO));
        return responseHandle(responseDTO);
    }

    public BaseDownLoadResponse<List<OrderItemStatisticsResponse>> queryOrderItemStatistics(OrderConditionsReq request) {
        long begin = System.currentTimeMillis();
        BaseDownLoadResponse<List<OrderItemStatisticsResponse>> responseDTO = RequestThirdPartyUtils.httpJsonReqComplexDownLoad(restTemplate, InterfaceAddressConstant.QUERY_ORDER_ITEM_STATISTICS,
                createBaseRequest(request, ""), new ParameterizedTypeReference<BaseDownLoadResponse<List<OrderItemStatisticsResponse>>>() {
                });
        ThirdPartyLog.infoConvertJson(begin, System.currentTimeMillis(), InterfaceAddressConstant.QUERY_ORDER_BY_SCROLL, request, responseMini(responseDTO));
        return responseDTO;
    }

    /**
     * 分页查询售后单
     *
     * @param queryRequest
     * @param trackingNo
     * @return
     */
    public AfterSalesListResp queryAfterSalesOrderConditions(QueryAfterSalesOrderConditionsReq queryRequest, String trackingNo) {
        AfterSalesListResp responseDTO = RequestThirdPartyUtils.httpJsonReqComplexNew(restTemplate, InterfaceAddressConstant.QUERY_AFT_SALE_ORDER_LIST,
                createBaseRequest(queryRequest, trackingNo), new ParameterizedTypeReference<AfterSalesListResp>() {
                });
        return responseDTO;
    }

    /**
     * 售后单查询下载
     * @param request
     * @param trackingNo
     * @return
     */
    public BaseDownLoadResponse queryAfterSalesOrderByScrollId(QueryOrderByScrollRequest request, String trackingNo) {
        long begin = System.currentTimeMillis();
        BaseDownLoadResponse<List<AfterSalesOrderResp>> responseDTO = RequestThirdPartyUtils.httpJsonReqComplexDownLoad(restTemplate, InterfaceAddressConstant.QUERY_ORDER_AFTER_SALE_DOWN,
                createBaseRequest(request, trackingNo), new ParameterizedTypeReference<BaseDownLoadResponse<List<AfterSalesOrderResp>>>() {
                });
        ThirdPartyLog.infoConvertJson(begin, System.currentTimeMillis(), InterfaceAddressConstant.QUERY_ORDER_AFTER_SALE_DOWN, request, responseMini(responseDTO));
        return responseHandle(responseDTO);
    }

    /**
     * 根据订单号查询订单详情
     *
     * @param partnerId
     * @param orderCode
     * @param trackingNo
     * @return
     */
    public QueryByCodeResponse queryOrderByCode(String partnerId, String orderCode, String trackingNo) {
        String url = InterfaceAddressConstant.QUERY_ORDER_BY_CODE + "?orderCode=" + orderCode + "&partnerId=" + partnerId;
        QueryByCodeResponse queryResponse = RequestThirdPartyUtils.httpGetReqComplex(this.restTemplate, url
                , createBaseRequest(null, trackingNo), new ParameterizedTypeReference<QueryByCodeResponse>() {
                });
        // fisherman 【ID1029765】 【技术线】【订单】订单ES服务订单数据查询热数据从DB(Redis)获取
         return checkTime(partnerId ,queryResponse);
    }

    /**
     * 根据订单号查询订单详情
     *
     * @param partnerId
     * @param orderCode
     * @param trackingNo
     * @param orderCode
     * @param trackingNo
     * @return
     */
    public QueryByCodeResponse queryOrderByCode(String partnerId, String orderCode, String trackingNo,Long startTimestamp,Long endTimestamp) {
        String url = InterfaceAddressConstant.QUERY_ORDER_BY_CODE + "?orderCode=" + orderCode + "&partnerId=" + partnerId+ "&startTimestamp=" + startTimestamp+ "&endTimestamp=" + endTimestamp;
        QueryByCodeResponse queryResponse = RequestThirdPartyUtils.httpGetReqComplex(this.restTemplate, url
                , createBaseRequest(null, trackingNo), new ParameterizedTypeReference<QueryByCodeResponse>() {
                });
        return queryResponse;
    }

    /**
     * es查询停车场订单
     */
    public BaseDownLoadResponse<List<OrderInfoReqs>> queryParkingOrderConditions(ParkingOrderConditionsReq request, String trackingNo) {
        long begin = System.currentTimeMillis();
        BaseDownLoadResponse<List<OrderInfoReqs>> responseDTO = RequestThirdPartyUtils.httpJsonReqComplexDownLoad(restTemplate, InterfaceAddressConstant.QUERY_PARKING_ORDER_BY_CONDITIONS,
                createBaseRequest(request, trackingNo), new ParameterizedTypeReference<BaseDownLoadResponse<List<OrderInfoReqs>>>() {
                });
        ThirdPartyLog.infoConvertJson(begin, System.currentTimeMillis(), InterfaceAddressConstant.QUERY_PARKING_ORDER_BY_CONDITIONS, request, responseMini(responseDTO));
        return responseHandle(responseDTO);
    }



    BaseDownLoadResponse responseMini(BaseDownLoadResponse responseDTO){

        BaseDownLoadResponse baseDownLoadResponse = new BaseDownLoadResponse();

        if(responseDTO == null){
            return baseDownLoadResponse;
        }

        baseDownLoadResponse.setCode(responseDTO.getCode());
        baseDownLoadResponse.setMessage(responseDTO.getMessage());
        baseDownLoadResponse.setVer(responseDTO.getVer());
        baseDownLoadResponse.setScrollId(responseDTO.getScrollId());
        baseDownLoadResponse.setTotalNum(responseDTO.getTotalNum());
        baseDownLoadResponse.setNumber(responseDTO.getNumber());

        return baseDownLoadResponse;
    }

    /**
     * 小助手营业额统计查询
     */
    public BaseResponse<OrderStatisticsResp> queryOrderStatistics(OrderConditionsReq request, String trackingNo) {
        BaseResponse<OrderStatisticsResp> responseDTO = RequestThirdPartyUtils.httpJsonReqComplexDownLoad(restTemplate, InterfaceAddressConstant.QUERY_ORDER_STATISTICS,
                createBaseRequest(request, trackingNo), new ParameterizedTypeReference<BaseResponse<OrderStatisticsResp>>() {
                });
        return responseDTO;
    }

    private <T> BaseDownLoadResponse<T> responseHandle(BaseDownLoadResponse<T> responseDTO) {
        BaseDownLoadResponse baseDownLoadResponse = new BaseDownLoadResponse();
        if (responseDTO == null) {
            baseDownLoadResponse.setCode(ResponseResultEnum.SYSTEM_BUSINESS_ERROR.getCode());
            baseDownLoadResponse.setMessage(ResponseResultEnum.SYSTEM_BUSINESS_ERROR.getMessage());
            return baseDownLoadResponse;
        }
        if (!Objects.equals(SUCCESS_RESPONSE_CODE, responseDTO.getCode())) {
            baseDownLoadResponse.setCode(ResponseResultEnum.SYSTEM_BUSINESS_ERROR.getCode());
            baseDownLoadResponse.setMessage(responseDTO.getMessage());
            return baseDownLoadResponse;
        }
        BaseDownLoadResponse<T> result = new BaseDownLoadResponse<>();
        result.setCode(responseDTO.getCode());
        result.setMessage(responseDTO.getMessage());
        result.setResult(responseDTO.getResult());
        result.setVer(responseDTO.getVer());
        result.setScrollId(responseDTO.getScrollId());
        result.setTotalNum(responseDTO.getTotalNum());
        return result;
    }

    private <T> BaseRequest<T> createBaseRequest(T req, String trackingNo) {
        BaseRequest<T> request = new BaseRequest<>();
        request.setRequestBody(req);
        request.setAppName(orderCenterProperties.getAppName());
        request.setBaseUrl(orderCenterProperties.getBaseUrl());
        request.setTrackingNo(trackingNo);
        return request;
    }


    /**
     *  批量查询
     *  【ID1029765】 【技术线】【订单】订单ES服务订单数据查询热数据从DB(Redis)获取
     * @param responseDTO
     */
    private void batchCheckTime(OrderConditionsReq request,BaseDownLoadResponse<List<OrderInfoReqs>> responseDTO) {
        // 商户级别配置开关 是否需要数据替换操作
        if (!checkConfig(request.getPartnerId())){
            return;
        }
        if (responseDTO == null || CollectionUtils.isEmpty(responseDTO.getResult())) {
            return;
        }
        List<OrderInfoReqs> result = responseDTO.getResult();
        // 过滤 需要查询 redis 的 ordercode
        List<String> orderCodes = result.stream().
                filter(orderInfoReqs -> isAfterTime(orderInfoReqs.getUpdateTime()))
                .map(OrderInfoReqs::getOrderCode).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(orderCodes)) {
            return;
        }
        try {
            logUtil.info("进入redis 数据替换 ES 逻辑", LogThreadLocal.getTrackingNo(), null);
            // 查询redis
            BatchQueryByCodesReq batchQueryByCodesReq = new BatchQueryByCodesReq();
            batchQueryByCodesReq.setOrderCodes(orderCodes);
            BaseResponse<List<OrderInfoReqs>> redisResponse = orderSdkService.batchQueryByCodes(batchQueryByCodesReq, LogThreadLocal.getTrackingNo());
            logUtil.info("list 热点数据查询redis, ",batchQueryByCodesReq,redisResponse);
            if (CollectionUtils.isEmpty(redisResponse.getResult())) {
                return ;
            }
            // 替换原有查询结果
            List<OrderInfoReqs> orderInfoReqs = replaceData(result, redisResponse.getResult());
            logUtil.info("list 替换 结果 ",result,orderInfoReqs);
            responseDTO.setResult(orderInfoReqs);
        }catch (Exception e){
            // 不要影响主流程
            logUtil.info("Redis替换ES异常 error",responseDTO, e);
        }
    }

    /**
     *  校验 是否需要走 ES热点数据替换
     * @param partnerId
     * @return true 需要,  false 不需要
     */
    private boolean checkConfig(String partnerId) {
        // 查询参数没传递 partnerId
        if (Objects.isNull(partnerId)) {
            return false;
        }
        // 查询时间
        if (orderCenter.getRedisToEsTimeLimit() < 0) {
            return false;
        }
        // 没有配置商户
        List<String> redisToEsPartnerIds = orderCenter.getRedisToEsPartnerIds();
        if (CollectionUtils.isEmpty(redisToEsPartnerIds)) {
            return false;
        }
        return redisToEsPartnerIds.contains(partnerId);
    }

    /**
     *  替换原有查询结果  需要考虑替换的时间复杂度
     *  用流 拿出 原有的数据  + 现有数据 (有排序功能 不能使用这种方式)
      * @param to  需要替换的数据
     * @param from  新数据
     */
    private List<OrderInfoReqs> replaceData(List<OrderInfoReqs> to, List<OrderInfoReqs> from) {
        if (CollectionUtils.isEmpty(to) || CollectionUtils.isEmpty(from)) {
            return to;
        }
        // 这里还可以优化  暂时先上线
        from.forEach(orderInfoReqs -> {
            for (int i = 0; i < to.size(); i++) {
                OrderInfoReqs infoReqs = to.get(i);
                if (orderInfoReqs.getOrderCode().equals(infoReqs.getOrderCode())) {
                    to.set(i,orderInfoReqs);
                    break;
                }
            }
        });
        return to;
    }

    /**
     * 更新时间在6小时以内，则根据orderCode调用DB(Redis)查询一次并替换该订单对象
     * @param partnerId 商户级别开关控制
     * @param queryResponse
     * @return
     */
    private QueryByCodeResponse checkTime(String partnerId,QueryByCodeResponse queryResponse) {
        // 商户级别开关控制 fisherman
        logUtil.info("获取到的商户级别配置, timeLimit:{} redisToEsPartnerIds:{}",orderCenter.getRedisToEsTimeLimit(),orderCenter.getRedisToEsPartnerIds());
        // 商户级别配置开关 是否需要数据替换操作
        if (!checkConfig(partnerId)){
            return queryResponse;
        }
        if (queryResponse ==null || queryResponse.getResult() ==null) {
            return queryResponse;
        }
        OrderInfoReqs infoReqs = queryResponse.getResult();
        String strtime = infoReqs.getUpdateTime();
        if (Objects.isNull(strtime)) {
            return queryResponse;
        }
        if (isAfterTime(strtime)) {
            // 在 6小时范围内 ,就查询 redis 进行 对象数据替换
            try {
                logUtil.info("进入redis 数据替换 ES 逻辑", LogThreadLocal.getTrackingNo(), null);
                BatchQueryByCodesReq batchQueryByCodesReq = new BatchQueryByCodesReq();
                batchQueryByCodesReq.setOrderCodes(Collections.singletonList(infoReqs.getOrderCode()));
                BaseResponse<List<OrderInfoReqs>> redisResponse = orderSdkService.batchQueryByCodes(batchQueryByCodesReq, LogThreadLocal.getTrackingNo());
                logUtil.info("热点数据查询redis, ",batchQueryByCodesReq,redisResponse);
                if (CollectionUtils.isEmpty(redisResponse.getResult())) {
                    return queryResponse;
                }
                List<OrderInfoReqs> result = redisResponse.getResult();
                result.forEach(orderInfoReqs -> {
                    if (infoReqs.getOrderCode().equals(orderInfoReqs.getOrderCode())) {
                        queryResponse.setResult(orderInfoReqs);
                    }
                });
                logUtil.info("替换 结果 ",result,queryResponse);
                return queryResponse;
            }catch (Exception e){
                // 不要影响主流程
                logUtil.error("Redis替换ES异常 queryResponse:{} error", e,queryResponse);
                return queryResponse;
            }
        }
        return queryResponse;
    }

    /**
     *
     * @param time  13位时间戳
     * @return
     */
    private boolean isAfterTime(String time) {
        Date dateTime = new Date(Long.parseLong(time));
        // 和设置的时间 进行对比
        Calendar calendar = Calendar.getInstance();
        // - 6 小时                                       注意 下面是 加 [负数]
        calendar.add(Calendar.HOUR,-orderCenter.getRedisToEsTimeLimit());
        Date limitDate = calendar.getTime();
        return dateTime.after(limitDate);
    }

}
