package com.inspect.task.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.inspect.analysis.domain.ResultAnalysis;
import com.inspect.analysis.mapper.ResultAnalysisMapper;
import com.inspect.base.core.constant.AlgConstants;
import com.inspect.base.core.sftp.SftpClient;
import com.inspect.base.core.sftp.SftpUploadEntity;
import com.inspect.base.core.utils.DateUtils;
import com.inspect.base.core.utils.HttpClientUtils;
import com.inspect.base.core.utils.StringUtils;
import com.inspect.calender.service.TaskCalendarGenerator;
import com.inspect.partrolresult.util.PrintUtil;
import com.inspect.resultmain.controller.PatrolTaskResultMainController;
import com.inspect.resultmain.domain.PatrolTaskResultMain;
import com.inspect.task.domain.DeviceConvert;

import com.inspect.task.domain.PatrolData;
import com.inspect.task.domain.PatrolTask;
import com.inspect.task.mapper.PatrolTaskMapper;
import com.inspect.task.service.IPatrolTaskService;

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

import com.inspect.taskstatus.domain.PatrolTaskStatus;
import com.inspect.taskstatus.mapper.PatrolTaskStatusMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.util.List;

@Slf4j
@EnableScheduling
@Service
public class PatrolTaskServiceImpl implements IPatrolTaskService {

    final PatrolTaskMapper patrolTaskMapper;

    @Autowired
    private PatrolTaskStatusMapper patrolTaskStatusMapper;

    @Autowired
    private PatrolTaskResultMainController patrolTaskResultMainController;

    @Autowired
    private TaskCalendarGenerator taskCalendarGenerator;
    @Autowired
    private SftpClient sftpClient;

    final ResultAnalysisMapper resultAnalysisMapper;

    @Autowired
    public PatrolTaskServiceImpl(PatrolTaskMapper patrolTaskMapper, ResultAnalysisMapper resultAnalysisMapper) {
        this.patrolTaskMapper = patrolTaskMapper;
        this.resultAnalysisMapper = resultAnalysisMapper;
    }

    public PatrolTask selectPatrolTaskByTaskId(Long taskId) {
        return this.patrolTaskMapper.selectPatrolTaskByTaskId(taskId);
    }

    public String selectConfigByKey(String taskId) {
        return this.patrolTaskMapper.selectConfigByKey(taskId);
    }

    public List<PatrolTask> selectPatrolTaskList(PatrolTask patrolTask) {
        return patrolTaskMapper.selectPatrolTaskList(patrolTask);
    }

    public List<Map<String, String>> selectBasedataBdConfigDeviceConvert(DeviceConvert deviceConvert) {
        return this.patrolTaskMapper.selectBasedataBdConfigDeviceConvert(deviceConvert);
    }

    public List<Map<String, Object>> selectBaseDevice(String areaCode) {
        return this.patrolTaskMapper.selectBaseDevice(areaCode);
    }

    public Map<String, Object> selectBaseDeviceByCode(String devCode) {
        return this.patrolTaskMapper.selectBaseDeviceByCode(devCode);
    }

    public List<Map<String, Object>> selectBasePoint(String devId) {
        return this.patrolTaskMapper.selectBasePoint(devId);
    }

    public List<Map<String, Object>> selectBasePointByPointId(String pointId) {
        return this.patrolTaskMapper.selectBasePointByPointId(pointId);
    }

    public List<Map<String, Object>> selectBasePointByBj(String devId) {
        return this.patrolTaskMapper.selectBasePointByBj(devId);
    }

    public List<Map<String, Object>> selectBasePointPre(String pointId) {
        return this.patrolTaskMapper.selectBasePointPre(pointId);
    }

    public Map<String, Object> selectBaseEqBook(String eqId) {
        return this.patrolTaskMapper.selectBaseEqBook(eqId);
    }

    public int insertPatrolTask(PatrolTask patrolTask) {
        patrolTask.setCreateTime(DateUtils.getNowDate());
        this.patrolTaskMapper.insertPatrolTask(patrolTask);

        taskCalendarGenerator.onTaskChange();
        return patrolTask.getTaskId().intValue();
    }

    public int updatePatrolTask(PatrolTask patrolTask) {
        int count = this.patrolTaskMapper.updatePatrolTask(patrolTask);
        taskCalendarGenerator.onTaskChange();
        return count;
    }

    public int updatePatrolTaskTime(String taskId) {
        int count = this.patrolTaskMapper.updatePatrolTaskTime(taskId);
        taskCalendarGenerator.onTaskChange();
        return count;
    }

    public int deletePatrolTaskByTaskIds(Long[] taskIds) {
        int count = this.patrolTaskMapper.deletePatrolTaskByTaskIds(taskIds);
        taskCalendarGenerator.onTaskChange();
        return count;
    }

    public int deletePatrolTaskByTaskId(Long taskId) {
        int count = this.patrolTaskMapper.deletePatrolTaskByTaskId(taskId);
        taskCalendarGenerator.onTaskChange();
        return count;
    }

    public List<Map<String, Long>> selectTaskRationalGroupByType() {
        return patrolTaskMapper.selectTaskRationalGroupByType();
    }

    public List<Map<String, String>> defectList1() {
        return this.resultAnalysisMapper.defectList1();
    }

    public List<Map<String, String>> defectList2() {
        return this.resultAnalysisMapper.defectList2();
    }

    public List<Map<String, String>> defectList3() {
        return this.resultAnalysisMapper.defectList3();
    }

    public List<Map<String, String>> pointStatistics() {
        return this.resultAnalysisMapper.pointStatistics();
    }

    @Override
    public boolean correctionAlgorithm(PatrolData patrolData) {
        log.info("controller correctionAlgorithm pointId: {}, resValue: {}",
                patrolData.getPointId(),
                patrolData.getResValue());
        final Map<String, Object> result = patrolTaskMapper.selectChannelCodeByPatrolPointId(patrolData.getPointId());
        final String channelCode = (String) result.get("channel_code");
        final String presetPosCode = (String) result.get("preset_pos_code");
        final String presetPosName = (String) result.get("preset_pos_name");
        final Integer patrolPointId = (Integer) result.get("patrol_point_id");
        final String videoNvrCode = (String) result.get("video_nvr_code");
        log.info("controller correctionAlgorithm channelCode: {}, presetPosCode: {}, presetPosName: {}, patrolPointId: {}, videoNvrCode: {}",
                channelCode,
                presetPosCode,
                presetPosName,
                patrolPointId,
                videoNvrCode);
        // 转到预置位
        try {
            final String url2 = "http://199.199.199.154:9906" + "/api/v1/control/preset";
            final String param2 = "serial=" + videoNvrCode
                    + "&command=goto&preset=" + presetPosCode
                    + "&code=" + channelCode
                    + "&name=" + URLEncoder.encode(presetPosName, ("UTF-8"))
                    + "&id=" + patrolPointId
                    + "&host=" + "null"
                    + "&port=" + "null"
                    + "&username=" + "null"
                    + "&password=" + "null"
                    + "&address=" + "null";
            log.info("controller correctionAlgorithm preset url2: {}, param2: {}", url2, param2);
            HttpClientUtils.get(url2, param2);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }

        try {
            Thread.sleep(20000);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }

        ObjectMapper mapper = new ObjectMapper();
        List<List<Integer>> list;
        ResultAnalysis resultAnalysis = new ResultAnalysis();
        resultAnalysis.setTaskPatrolId(patrolData.getTaskPatrolId());
        resultAnalysis.setObjectId(patrolData.getPointId());
        resultAnalysis.setAlgType(AlgConstants.CORRECTION);
        try {
            List<ResultAnalysis> resultAnalysisList = resultAnalysisMapper.selectResultAnalysisList(resultAnalysis);
            if (!resultAnalysisList.isEmpty()) {
                resultAnalysis = resultAnalysisList.get(0);
                list = mapper.readValue(resultAnalysis.getResValue(), new TypeReference<List<List<Integer>>>() {
                });
            } else {
                list = new ArrayList<>();
            }
            log.info("controller correctionAlgorithm correction value: {}", list);
        } catch (Exception e) {
            log.info("controller correctionAlgorithm correction value exception");
            list = new ArrayList<>();
        }

        String controlPara1 = "";
        String controlPara2 = "";
        if (list.size() == 2 && list.get(0).size() == 2 && list.get(1).size() == 2) {
            controlPara1 = list.get(0).get(0) + "," + list.get(0).get(1);
            controlPara2 = list.get(1).get(0) + "," + list.get(1).get(1);
        }

        final String url = "http://199.199.199.154:9906" + "/api/v1/control/presetEx";
        final String param = "command=correction"
                + "&code=" + channelCode
                + "&controlCode=" + "31"
                + "&controlPara1=" + controlPara1
                + "&controlPara2=" + controlPara2;
        log.info("controller correctionAlgorithm correction param: {}", param);
        // 设置预置位
        try {
            HttpClientUtils.get(url, param);
            Thread.sleep(5000);
            // 保存预置位
            final String url3 = "http://199.199.199.154:9906" + "/api/v1/control/presetEx";
            final String param3 = "command=correctionSet"
                    + "&code=" + channelCode
                    + "&preset=" + presetPosCode
                    + "&name=" + URLEncoder.encode(presetPosName, ("UTF-8"));
            try {
                HttpClientUtils.get(url3, param3);
            } catch (Exception e) {
                log.info("controller correctionAlgorithm url3 execute exception: {}", e.getMessage());
            }
        } catch (Exception e) {
            log.info("controller correctionAlgorithm HttpClientUtils.get execute exception: {}", e.getMessage());
        }
        // 抓拍新点位图片
        final String urlCapture = "http://199.199.199.154:9906" + "/api/v1/device/channelsnap"
                + "?serial=" + videoNvrCode
                + "&realtime=true"
                + "&code=" + channelCode;

        String fileTypeDir = "snap/";
        String fileName = "correction_" + System.currentTimeMillis() + ".jpg";
        String filePath = "";
        try {
            String[] split = urlCapture.split("\\?");
            SftpUploadEntity sftpUploadEntity = new SftpUploadEntity(HttpClientUtils.getStream(split[0], split[split.length - 1]));
            sftpUploadEntity.setFilePath(fileTypeDir);
            sftpUploadEntity.setFileName(fileName.split(StringUtils.HASHTAG)[0]);
            filePath = sftpClient.upload(sftpUploadEntity);
        } catch (Exception e) {
            log.info("correction ftp error:{}", e.getMessage());
        }

        // 更新结果
        if (!StringUtils.isEmpty(patrolData.getLineId()) && filePath != "") {
            resultAnalysis.setResStatus("4");
            resultAnalysis.setDescription("已完成纠偏");
            resultAnalysis.setOriginalValue(filePath);
            resultAnalysisMapper.updateResultAnalysis(resultAnalysis);
            log.info("controller correctionAlgorithm updateResultAnalysis: {}", resultAnalysis);
            return true;
        }
        return false;
    }

    /**
     * 异步执行
     */
    @Async
    public void executeAsync(PatrolTaskStatus taskStatus) {
        String stationNo = patrolTaskMapper.selectStationNo();
        long startTime = System.currentTimeMillis();
        log.debug("异步执行任务报告合并，任务: {}", taskStatus);
        String taskName = taskStatus.getTaskName();
        if (!"lingzhouzhiliu".equals(stationNo) || StringUtils.isEmpty(taskName) || !taskName.contains("_")) {
            return;
        }
        String[] taskNames = StringUtils.split(taskName, "_");
        String taskAreaName = taskNames[0];
        // 根据区域名查询该区域的任务数量
        List<PatrolTask> patrolAreaTasks = patrolTaskMapper.selectPatrolTaskListByTaskAreaName(taskAreaName + "_");
        log.debug("异步执行任务报告合并，区域: {} 下的任务: {}", taskAreaName, patrolAreaTasks);
        // 换流变_ 14个
        // 直流场_ 6个
        log.debug("异步执行任务报告合并，区域: {} 下的任务数量: {}", taskAreaName, patrolAreaTasks.size());
        if (patrolAreaTasks.size() == 0) {
            return;
        }
        Set<String> patrolTaskCodes = patrolAreaTasks.stream().map(PatrolTask::getTaskCode).collect(Collectors.toSet());
        log.info("异步执行任务报告合并，区域: {} 下的任务编码集合: {}", taskAreaName, patrolTaskCodes);

        // patrolTaskStatus 和 patrolTaskResultMain 关联查询，区域任务执行状态已完成，并且未归档的数量是否和区域任务总数相等，相等则归档该区域的任务

        // 查询区域任务执行状态已完成，并且未归档的数量是否和区域任务总数相等，相等则归档该区域的任务
        List<JSONObject> jsonObjects = patrolTaskMapper.selectPatrolTaskStatus(patrolTaskCodes);
        log.debug("异步执行任务报告合并，区域: {} 下的已完成任务集合: {}", taskAreaName, jsonObjects);
        Set<String> taskCodeStatus = jsonObjects.stream().map(jsonObject -> jsonObject.getString("taskCode")).collect(Collectors.toSet());
        log.info("异步执行任务报告合并，区域: {} 下的任务编码集合: {}", taskAreaName, taskCodeStatus);

        // 如果patrolTaskCodes 都在taskCodeStatus中，则归档该区域的任务
        if (!taskCodeStatus.containsAll(patrolTaskCodes)) {
            return;
        }
        List<Long> lineIds = jsonObjects.stream().map(jsonObject -> jsonObject.getLong("lineId")).distinct().collect(Collectors.toList());

        PatrolTaskResultMain patrolTaskResultMain = new PatrolTaskResultMain();
        patrolTaskResultMain.setLineIds(lineIds);
        patrolTaskResultMain.setCheckPerson("admin");
//        patrolTaskResultMainController.updateInfo_lingzhou(patrolTaskResultMain);
        PrintUtil.useTime("异步执行任务报告合并，区域: " + taskAreaName + " 下的任务归档完成", startTime);

    }

    //     定时任务归档（每天18:30执行）
    @Scheduled(cron = "0 30 23 * * ?")
    public void executeTask() {
        String stationNo = patrolTaskMapper.selectStationNo();
        if (!"lingzhouzhiliu".equals(stationNo)) {
            return;
        }
        log.info("=============================定时任务归档开始了=============================================");
        List<JSONObject> jsonObjects = patrolTaskMapper.selectPatrolTaskStatus(new HashSet<>());
        List<Long> lineIds = jsonObjects.stream().map(jsonObject -> jsonObject.getLong("lineId")).distinct().collect(Collectors.toList());
        log.info("定时任务归档，已完成任务集合guidang lineIds: {}", lineIds);
        PatrolTaskResultMain patrolTaskResultMain = new PatrolTaskResultMain();
        patrolTaskResultMain.setLineIds(lineIds);
        patrolTaskResultMain.setCheckPerson("admin");
        try {
            patrolTaskResultMainController.updateInfo_lingzhou(patrolTaskResultMain);
        } catch (Exception e) {
            log.error("定时任务归档异常", e);
        }
        log.info("=============================定时任务归档结束了=============================================");
    }

    // 根据点位id查询点位信息
    @Override
    public List<JSONObject> selectBasedataPatrolPointList(List<String> patrolPointIds) {
        return patrolTaskMapper.selectBasedataPatrolPointList(patrolPointIds);
    }

    @Override
    public List<JSONObject> selectBasedataPatrolPointPresetList(List<String> patrolPointIds) {
        return patrolTaskMapper.selectBasedataPatrolPointPresetList(patrolPointIds);
    }

    @Override
    public List<JSONObject> selectPatrolPresetPosList(List<String> patrolPointIds) {
        return patrolTaskMapper.selectPatrolPresetPosList(patrolPointIds);
    }
}
