package com.inspect.partrolresult.service;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.pagehelper.util.StringUtil;
import com.inspect.analysis.constant.AnalyseConstants;
import com.inspect.analysis.domain.AnalyseLog;
import com.inspect.analysis.service.IAnalyseLogService;
import com.inspect.base.core.constant.AlgConstants;
import com.inspect.base.core.constant.RedisConst;
import com.inspect.base.core.sftp.SftpClient;
import com.inspect.base.core.utils.DateUtils;
import com.inspect.base.core.utils.HttpClientUtils;
import com.inspect.base.core.utils.StringUtils;
import com.inspect.base.redis.service.RedisService;
import com.inspect.partrolresult.domain.AnalyseReqItem;
import com.inspect.partrolresult.domain.AnalyseRequest;
import com.inspect.partrolresult.util.XmpUtil;
import com.inspect.task.service.IPatrolTaskService;
import com.inspect.taskstatus.domain.PatrolTaskStatus;
import com.inspect.taskstatus.service.IPatrolTaskStatusService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Slf4j
@Component
public class AnalyseRequestServiceImpl implements IAnalyseRequestService {
    private static final Set<String> INFRARED_TYPES = new HashSet<>(Arrays.asList(
            AlgConstants.INFRA_1800,
            AlgConstants.INFRA_YU3,
            AlgConstants.INFRA_CAMERA,
            AlgConstants.INFRA_CAMERA_REVERSE
    ));
    private static final Set<String> INFRARED_TYPES_2 = new HashSet<>(Arrays.asList(

            AlgConstants.INFRA_CAMERA_REVERSE
    ));
    private static final Set<String> OLD_INFRARED_TYPES = new HashSet<>(Arrays.asList(
            "infrared"
    ));
    private static final Set<String> METER_TYPES = new HashSet<>(Arrays.asList(
            AlgConstants.METER
    ));
    private static final Set<String> GIS_METER_TYPES = new HashSet<>(Arrays.asList(
            AlgConstants.GIS_METER_2
    ));
    @Resource
    private RedisService redisService;
    @Value("${task.test-mode:false}")
    private boolean testMode;
    @Value("${server.port}")
    private String port;
    @Value("${task.drone-xmp:false}")
    private boolean droneXmpEnabled;
    @Resource
    private IPatrolTaskService patrolTaskService;
    @Resource
    private AnalyseRequestRetryableDelegate retryDelegate;
    @Resource
    private DelayQueueService<String> delayQueueService;
    @Resource
    private IAnalyseLogService analysisLogService;
    @Resource
    private IPatrolTaskStatusService patrolTaskStatusService;
    @Resource
    private SftpClient sftpClient;

    public static boolean checkInfraredType(String[] typeList) {
        if (typeList == null) {
            return false;
        }
        for (String type : typeList) {
            if (INFRARED_TYPES.contains(type)) {
                return true;
            }
        }
        return false;
    }

    public static boolean checkInfraredType2(String[] typeList) {
        if (typeList == null) {
            return false;
        }
        for (String type : typeList) {
            if (INFRARED_TYPES_2.contains(type)) {
                return true;
            }
        }
        return false;
    }

    public static boolean checkOldInfraredType(String[] typeList) {
        if (typeList == null) {
            return false;
        }
        for (String type : typeList) {
            if (OLD_INFRARED_TYPES.contains(type)) {
                return true;
            }
        }
        return false;
    }

    public static boolean checkMeterType(String[] typeList) {
        if (typeList == null) {
            return false;
        }
        for (String type : typeList) {
            if (METER_TYPES.contains(type)) {
                return true;
            }
        }
        return false;
    }

    public static boolean checkGisMeter2Type(String[] typeList) {
        if (typeList == null) {
            return false;
        }
        for (String type : typeList) {
            if (GIS_METER_TYPES.contains(type)) {
                return true;
            }
        }
        return false;
    }

    public static void main(String[] args) {
        try {
            ObjectMapper mapper = new ObjectMapper();

            AnalyseRequest r1 = new AnalyseRequest();
            r1.setRequestId("3177fe1c5d6f44f7bc527d5de8451ab9");
            String json = mapper.writeValueAsString(r1);

            AnalyseRequest r2 = mapper.readValue(json, AnalyseRequest.class);
            boolean res = r1.equals(r2);
            System.out.println(res); // 应为 true
            boolean res2 = r1.hashCode() == r2.hashCode();
            System.out.println(res2); // 应为 true
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    //qinyl
    @Override
    public void sendRequest(AnalyseRequest analyseReq, String[] typeList, boolean isFilter) throws IOException {
        final long requestTimeout = 1L;
        // 数聚的初筛和大模型不能使用同一requestId
        String requestId = UUID.randomUUID().toString().trim().replaceAll(StringUtils.DASH, StringUtils.EMPTY);
//        String requestId = StringUtils.isNotEmpty(analyseReq.getRequestId()) ?
//                analyseReq.getRequestId() : UUID.randomUUID().toString().trim().replaceAll(StringUtils.DASH, StringUtils.EMPTY);
        String taskPatrolId = analyseReq.getTaskPatrolId();
        redisService.setCacheObject(RedisConst.REQUEST_UUID + requestId, taskPatrolId, requestTimeout, TimeUnit.DAYS);
        log.info("CALL_REMOTE_ANALYZE isFilter: {}, requestId: {}, typeList: {}", isFilter, requestId, typeList);

        analyseReq.setRequestId(requestId);
        String taskSetKey = AnalyseConstants.ANALYSE_TASK_REQUEST + taskPatrolId;
        //String requestSetKey = AnalyseConstants.ANALYSE_REQUEST_ALG + requestId;

        redisService.setCacheObject(AnalyseConstants.ANALYSE_REQUEST_ID.concat(requestId), taskPatrolId, requestTimeout, TimeUnit.DAYS);
        redisService.redisTemplate.opsForSet().add(taskSetKey, requestId);
        redisService.expire(taskSetKey, requestTimeout, TimeUnit.DAYS);

        String requestUrl;
        String analyseFilter = patrolTaskService.selectConfigByKey(AnalyseConstants.ANALYSE_IS_FILTER);
        if ("1".equals(analyseFilter) && isFilter) {
            final String analyzeFilterRequestIdRedisKey = AnalyseConstants.ANALYSE_FILTER_REQUEST.concat(requestId);
            log.info("SEND_REQUEST_FILTER taskPatrolId: {}, requestId: {}, analyseFilterRequestIdRedisKey: {}, analyseReq: {}",
                    analyseReq.getTaskPatrolId(),
                    requestId,
                    analyzeFilterRequestIdRedisKey,
                    analyseReq);
            //redisService.setCacheObject(analyzeFilterRequestIdRedisKey, analyseReq.clone(), testMode?3L:requestTimeout, testMode?TimeUnit.MINUTES:TimeUnit.DAYS);
            redisService.setCacheObject(analyzeFilterRequestIdRedisKey, analyseReq.clone());
//            if(testMode) {
//                delayQueueService.submitRequest(AnalyseConstants.ANALYSE_REQ_DELAY_QUEUE, analyseReq, (3L), TimeUnit.MINUTES);
//            } else {
//                delayQueueService.submitRequest(AnalyseConstants.ANALYSE_REQ_DELAY_QUEUE, analyseReq, requestTimeout, TimeUnit.DAYS);
//            }
            AnalyseReqItem analyseReqItem = analyseReq.getObjectList().get(0);//只取第一个
            analyseReqItem.setTypeList(typeList);
            analyseReq.setObjectList(Collections.singletonList(analyseReqItem));
            if (checkOldInfraredType(typeList)) {
                log.info("ANALYSIS_FILTER_URL_OLD_INFRARED requestId: {}, analyseReq: {}", requestId, analyseReq);
                if (testMode) {
                    delayQueueService.submitRequest(AnalyseConstants.ALGORITHM_REQUEST_DELAY_QUEUE, analyseReq.getRequestId(), (3L), TimeUnit.MINUTES);
                } else {
                    delayQueueService.submitRequest(AnalyseConstants.ALGORITHM_REQUEST_DELAY_QUEUE, analyseReq.getRequestId(), requestTimeout, TimeUnit.DAYS);
                }
                sendCompensateRequest(analyseReq);
                return;
            }

//            if (checkInfraredType2(typeList)) {
//                requestUrl = patrolTaskService.selectConfigByKey(AnalyseConstants.ANALYSE_FILTER_URL_INFRARED);
//                log.info("ANALYSE_FILTER_URL_INFRARED requestId: {}, requestUrl: {}", requestId, requestUrl);
//            } else
            {
                requestUrl = getFilterAnalysisUrl(requestId, analyseReq.getDrafter());
                log.info("ANALYSE_FILTER_URL requestId: {}, requestUrl: {}", requestId, requestUrl);
            }

            // 初筛读取无机人图片XMP位姿信息
            if (droneXmpEnabled) {
                readDroneImageXmpInfo(analyseReq);
            }
        } else {
            // 获取大模型分析接口地址
            requestUrl = getLargeModelAnalysisUrl(typeList, requestId, analyseReq.getDrafter());

            final String analyzeBigModelRequestIdRedisKey = AnalyseConstants.ANALYSE_AI_REQUEST.concat(requestId);
            log.info("SEND_REQUEST_BIG_MODEL requestId: {}, analyzeBigModelRequestIdRedisKey: {}, analyseReq: {}",
                    requestId,
                    analyzeBigModelRequestIdRedisKey,
                    analyseReq);
            redisService.setCacheObject(analyzeBigModelRequestIdRedisKey, analyseReq.clone(), requestTimeout, TimeUnit.DAYS);
        }

        if (StringUtil.isEmpty(requestUrl)) {
            requestUrl = "http://localhost:8080";
            log.error("ANALYSIS URL IS EMPTY, isFilter: {}, requestId: {}, typeList: {}", isFilter, requestId, typeList);
        }

        analyseReq.setFilter(isFilter);
        analyseReq.setRequestUrl(requestUrl.concat(AnalyseConstants.ANALYSE_URI));
        analyseReq.setRedissonTime(DateUtils.parseDateToStr(DateUtils.yyyyMMddHHmmss, new Date()));

        if (testMode) {
            delayQueueService.submitRequest(AnalyseConstants.ALGORITHM_REQUEST_DELAY_QUEUE, analyseReq.getRequestId(), (3L), TimeUnit.MINUTES);
        } else {
            delayQueueService.submitRequest(AnalyseConstants.ALGORITHM_REQUEST_DELAY_QUEUE, analyseReq.getRequestId(), requestTimeout, TimeUnit.DAYS);
        }

        if (retryDelegate.callRemoteAnalyseService(analyseReq)) {
            log.info("CALL_REMOTE_ANALYSE SUCCESS, taskPatrolId: {}, requestId: {}",
                    analyseReq.getTaskPatrolId(),
                    analyseReq.getRequestId());

            final String objectId = analyseReq.getObjectList() != null && !analyseReq.getObjectList().isEmpty()
                    ? analyseReq.getObjectList().get(0).getObjectId() : "00000000";
            analysisLogService.log(
                    new AnalyseLog(("远端算法服务器收到请求"),
                            AnalyseConstants.ANALYSE_LOG_TYPE_SEND,
                            analyseReq.getTaskPatrolId(),
                            analyseReq.isFilter() ? "1" : "0",
                            requestId,
                            objectId,
                            requestUrl));
        } else {
            log.info("CALL_REMOTE_ANALYSE RETRYABLE FAIL, requestId: {}, taskPatrolId: {}",
                    analyseReq.getRequestId(),
                    analyseReq.getTaskPatrolId());
            final String objectId = analyseReq.getObjectList() != null && !analyseReq.getObjectList().isEmpty()
                    ? analyseReq.getObjectList().get(0).getObjectId() : "00000000";
            analysisLogService.log(
                    new AnalyseLog(analyseReq.isFilter() ? ("初筛远程服务器掉线") : ("大模型远程服务器掉线"),
                            AnalyseConstants.ANALYSE_LOG_TYPE_OFFLINE,
                            analyseReq.getTaskPatrolId(),
                            analyseReq.isFilter() ? "1" : "0",
                            requestId,
                            objectId,
                            requestUrl));
            throw new IOException("Remote analyse service failed");
        }
    }

    /**
     * 根据厂商获取初筛地址
     */
    public String getFilterAnalysisUrl(String requestId, String drafter) {
        String key = AnalyseConstants.ANALYSE_FILTER_URL;
        if (!StringUtil.isEmpty(drafter)) {
            key = "ANALYSE_FILTER_URL_" + drafter;
        }
        String requestUrl = patrolTaskService.selectConfigByKey(key);
        log.info("ANALYSIS_FILTER_URL requestId: {}, requestUrl: {}", requestId, requestUrl);
        return requestUrl;
    }

    /**
     * 根据厂商或算法获取大模型分析地址
     *
     * @param typeList  算法
     * @param requestId 请求唯一id标识
     * @param drafter   算法厂商
     * @return 大模型分析地址
     */
    public String getLargeModelAnalysisUrl(String[] typeList, String requestId, String drafter) {
        String requestUrl = "";

        // 根据厂商获取分析路径
        if (!StringUtil.isEmpty(drafter)) {
            String key = "ANALYSIS_BIG_URL_" + drafter;
            requestUrl = patrolTaskService.selectConfigByKey(key);
            log.info("{} requestId: {}, requestUrl: {}", key, requestId, requestUrl);
            if (!StringUtils.isEmpty(requestUrl)) {
                return requestUrl;
            }
        }

        // 红外分析路径
        if (checkInfraredType(typeList)) {
            requestUrl = patrolTaskService.selectConfigByKey(AnalyseConstants.ANALYSIS_BIG_URL_INFRARED);
            log.info("ANALYSIS_BIG_URL_INFRARED requestId: {}, requestUrl: {}", requestId, requestUrl);
        }
        // 表计读数分析路径
        else if (checkMeterType(typeList)) {
            requestUrl = patrolTaskService.selectConfigByKey(AnalyseConstants.ANALYSIS_BIG_URL_METER);
            log.info("ANALYSIS_BIG_URL_METER requestId: {}, requestUrl: {}", requestId, requestUrl);
        }
        // 无人机gis_meter2读数分析路径
        else if (checkGisMeter2Type(typeList)) {
            requestUrl = patrolTaskService.selectConfigByKey(AnalyseConstants.ANALYSIS_BIG_URL_GIS_METER_2);
            log.info("ANALYSIS_BIG_URL_GIS_METER_2 requestId: {}, requestUrl: {}", requestId, requestUrl);
        }
        // 默认大模型分析路径
        else {
            requestUrl = patrolTaskService.selectConfigByKey(AnalyseConstants.ANALYSIS_BIG_URL);
            log.info("DEFAULT ANALYSIS_BIG_URL requestId: {}, requestUrl: {}", requestId, requestUrl);
        }

        return requestUrl;
    }

    public void readDroneImageXmpInfo(AnalyseRequest analyseReq) {
        String taskPatrolId = analyseReq.getTaskPatrolId();
        PatrolTaskStatus taskStatus = patrolTaskStatusService.selectPatrolTaskStatusByTaskPatrolledId(taskPatrolId);
        if (taskStatus == null || !"2".equals(taskStatus.getPosType())) {
            return;
        }
        log.info("XMP reader, taskPatrolId:{}", taskPatrolId);

        List<AnalyseReqItem> imgUrlList = analyseReq.getObjectList();
        if (imgUrlList == null) {
            return;
        }

        for (AnalyseReqItem item : imgUrlList) {
            if (item == null || item.getImageUrlList() == null) {
                continue;
            }

            String[] imageUrlList = item.getImageUrlList();
            String[] droneDataList = new String[imageUrlList.length];

            for (int i = 0; i < imageUrlList.length; i++) {
                try {
                    String imageUrl = imageUrlList[i];
                    int finalI = i;
                    sftpClient.downLoad(imageUrl, (inputStream -> {
                        log.info("XMP imageUrl:{}", imageUrl);
                        String droneDataStr = XmpUtil.parseDrone(inputStream);
                        droneDataList[finalI] = droneDataStr;
                    }));
                } catch (Exception e) {
                    log.error("读取XMP失败", e.getMessage());
                }
            }
            item.setDronePoseList(droneDataList);
        }
    }

    public void sendCompensateRequest(AnalyseRequest request) {
        final String defaultUrl = "http://localhost:" + this.port + AnalyseConstants.ANALYSE_RET_URI;
        String[] typeList = request.getTypeList();
        if (typeList == null || typeList.length == 0) {
            log.info("SEND_COMPENSATE_REQUEST typeList empty: {}", request);
            return;
        }

        boolean containsInfrared = Arrays.asList(typeList).contains("infrared");
        log.info("SEND_COMPENSATE_REQUEST containsInfrared: {}, request: {}", containsInfrared, request);
        if (containsInfrared) {
            HttpClientUtils.sendPostAgain(defaultUrl, request.toInfraredResultStr());
        } else {
            HttpClientUtils.sendPostAgain(defaultUrl, request.toErrorResultStr());
        }
    }
}

