package com.hzjt.service;

import com.hzjt.domain.*;
import com.hzjt.mapper.SbtdspsrMapper;
import com.hzjt.mapper.TraffAlarmRecordMapper;
import com.hzjt.util.DateUtils;
import com.hzjt.util.FTPUtil;
import com.hzjt.util.StringEnum;
import com.hzjt.util.ThreadPoolUtil;
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.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import sun.misc.BASE64Encoder;
import tk.mybatis.mapper.entity.Condition;
import tk.mybatis.mapper.entity.Example;

import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

@Slf4j
@Service
public class EventWriteService {
    private static final String EVENT_SOURCE = "2";
    private static final String EVENT_SUPPLIER = "zksy";
    private static final String CONTAINS_EXIST = "交通事件已存在";

    @Autowired
    private RestTemplate restTemplate;

    @Value("${qingzhi.eventwrite.url}")
    private String url;

    @Value("${qingzhi.eventwrite.timeout}")
    private Integer timeout;

    @Autowired
    private TraffAlarmRecordMapper traffAlarmRecordMapper;
    @Autowired
    private SbtdspsrMapper sbtdspsrMapper;


    @Value("${qingzhi.redis.token}")
    private String qztoken;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;


    @Value("${alarmrecord.check.push.enable}")
    private String checkPushEnable;

    @Value("${alarmrecord.check.push.recordtype}")
    private String recordtype;

    @Autowired
    private TraffAlarmRecordMapper traffalarmrecordMapper;


    private static  CompletionService<ResultObj> completionService  = new ExecutorCompletionService<ResultObj>(ThreadPoolUtil.getPool());
    public ResultObj sendEvent(Long recordid) {
        Traffalarmrecord traffalarmrecord = traffalarmrecordMapper.selectByPrimaryKey(recordid);
        ResultObj resultObj;
        try {
            resultObj = sendMessage(traffalarmrecord);
        } catch (TimeoutException e) {
            log.error("eventwrite - sendEvent 请求超时:" + e.toString());
            return ResultObj.error(ResponseEnum.E_1008.getCode(), ResponseEnum.E_1008.getMsg());
        } catch (Exception e) {
            log.error("eventwrite - sendEvent 异常:" + e.toString());
            return ResultObj.error(ResponseEnum.E_9999.getCode(), e.toString());
        }
        return resultObj;
    }

    public List<ResultObj> sendEvents(List<Long> recordid) {
        Condition condition = new Condition(Traffalarmrecord.class);
        Example.Criteria criteria = condition.createCriteria();
        criteria.andIn("recordid",recordid);
        List<Traffalarmrecord> traffalarmrecordList = traffalarmrecordMapper.selectByCondition(condition);
        List<ResultObj> resultObj=new ArrayList<>();
        try {
            resultObj = sendAllMessage(traffalarmrecordList);

        } catch (TimeoutException e) {
            log.error("eventwrite - sendEvents 请求超时:" + e.toString());
            resultObj.add(ResultObj.error(ResponseEnum.E_1008.getCode(), ResponseEnum.E_1008.getMsg()));
        } catch (Exception e) {
            log.error("eventwrite - sendEvents 异常:" + e.toString());
             resultObj.add(ResultObj.error(ResponseEnum.E_9999.getCode(), e.toString()));
        }
        return resultObj;
    }

    private ResultObj sendMessage(Traffalarmrecord traffalarmrecord) throws InterruptedException, ExecutionException, TimeoutException {
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
        HttpEntity<Traffalarmrecord> requestEntity = new HttpEntity<>(traffalarmrecord, headers);
        return CompletableFuture.supplyAsync(() -> restTemplate.postForObject(url, requestEntity, ResultObj.class)).get(timeout, TimeUnit.SECONDS);
    }

    private List<ResultObj> sendAllMessage(List<Traffalarmrecord> traffalarmrecord) throws InterruptedException, ExecutionException, TimeoutException {
        List<ResultObj> objlist = new ArrayList<>();
        for (Traffalarmrecord record : traffalarmrecord) {
            completionService.submit(() -> {
                ResultObj obj = updateAndSendEvent(record);
                obj.setData(record.getRecordid());
                return obj;

            });
        }
        for (int i = 0; i < traffalarmrecord.size(); i++) {
            objlist.add(completionService.poll(10, TimeUnit.SECONDS).get());
        }
        return objlist;
    }

    public ResultObj updateAndSendEvent(Traffalarmrecord traffalarmrecord) {
        Long starttime = System.currentTimeMillis();
        EventWriteParam eventWriteParam = new EventWriteParam();
        eventWriteParam.setEventID(String.valueOf(traffalarmrecord.getRecordid()));
        eventWriteParam.setEventSource(EVENT_SOURCE);
        eventWriteParam.setRegionID(traffalarmrecord.getAreaid());
        eventWriteParam.setEventType(traffalarmrecord.getRecordtype());
        eventWriteParam.setOccurTime(DateUtils.formatDateToNoSign(traffalarmrecord.getRecordtime()));
        //获得外部编号
        List<Sbtdspsr> sbtdspsr = sbtdspsrMapper.selectBySbbh(traffalarmrecord.getFdid(),traffalarmrecord.getChannelid());

        eventWriteParam.setEventDeviceID(sbtdspsr.get(0).getWbbh());
        eventWriteParam.setEventSupplier(EVENT_SUPPLIER);
        BASE64Encoder base64Encoder = new BASE64Encoder();
        if(traffalarmrecord.getImg1path() != null ){
            byte[]  Img=FTPUtil.getFtpPicBytes(traffalarmrecord.getImg1path());
            eventWriteParam.setEventProof1(Img!=null?base64Encoder.encode(Img) : null);
        }

         if(traffalarmrecord.getImg2path() != null ){
             byte[]  Img=FTPUtil.getFtpPicBytes(traffalarmrecord.getImg2path());
            eventWriteParam.setEventProof2(Img!= null ? base64Encoder.encode(Img) : null);
         }
        if(traffalarmrecord.getImg3path() != null ) {
            byte[] Img = FTPUtil.getFtpPicBytes(traffalarmrecord.getImg3path());
            eventWriteParam.setEventProof3(Img != null ? base64Encoder.encode(Img) : null);

        }
        if(traffalarmrecord.getImg4path() != null ) {
            byte[] Img = FTPUtil.getFtpPicBytes(traffalarmrecord.getImg4path());
            eventWriteParam.setEventProof4(Img != null ? base64Encoder.encode(Img) : null);
        }
        if(traffalarmrecord.getImg5path() != null ) {
            byte[] Img = FTPUtil.getFtpPicBytes(traffalarmrecord.getImg5path());
            eventWriteParam.setEventProof5(Img != null ? base64Encoder.encode(Img) : null);
        }

        if(traffalarmrecord.getVideopath() != null ) {
            byte[] video = FTPUtil.getFtpPicBytes(traffalarmrecord.getVideopath());
            eventWriteParam.setEventvideo1(video != null ? base64Encoder.encode(video) : null);
        }
     //String strBase64 = new BASE64Encoder().encode(FTPUtil.getFtpPicBytes(strings.get(i).get("PICPATH1").toString()));

        WriteResultObj writeResultObj;
        Long endtime = System.currentTimeMillis();
        try {
            writeResultObj = sendMessage(eventWriteParam);
        } catch (TimeoutException e) {
            log.error("事件推送eventwrite - sendEvent 请求超时:"+"事件="+traffalarmrecord.toString()+",错误原因=" + e.toString()+",请求总消耗时长"+(endtime-starttime)+"毫秒，"+writeInfoStr(eventWriteParam));
            return ResultObj.error(ResponseEnum.E_1008.getCode(), ResponseEnum.E_1008.getMsg());
        } catch (Exception e) {
            log.error("事件推送eventwrite - sendEve" +
                    "nt 请求异常:"+"事件="+traffalarmrecord.toString()+",错误原因=" + e.toString()+",请求总消耗时长"+(endtime-starttime)+"毫秒，"+writeInfoStr(eventWriteParam));
            return ResultObj.error(ResponseEnum.E_9999.getCode(), e.toString());
        }
//        log.info("事件推送eventwrite - sendEvent 请求成功:"+"事件="+traffalarmrecord.toString()+",请求总消耗时长"+(endtime-starttime)+"毫秒，"+writeInfoStr(eventWriteParam));
        dealResult(writeResultObj, traffalarmrecord);
        return ResultObj.error(writeResultObj.getStatus(), writeResultObj.getMessage(), writeResultObj.getData());
    }

    private String writeInfoStr(EventWriteParam eventWriteParam){
        return  "图片1Base64长度:"+(eventWriteParam.getEventProof1()!=null?eventWriteParam.getEventProof1().length():0)+","
                +"图片2Base64长度:"+(eventWriteParam.getEventProof2()!=null?eventWriteParam.getEventProof2().length():0)+","
                +"图片3Base64长度:"+(eventWriteParam.getEventProof3()!=null?eventWriteParam.getEventProof3().length():0)+","
                +"图片4Base64长度:"+(eventWriteParam.getEventProof4()!=null?eventWriteParam.getEventProof4().length():0)+","
                +"图片5Base64长度:"+(eventWriteParam.getEventProof5()!=null?eventWriteParam.getEventProof5().length():0)+","
                +"视频流Base64长度:"+(eventWriteParam.getEventvideo1()!=null?eventWriteParam.getEventvideo1().length():0)+"。";
    }

    private WriteResultObj sendMessage(EventWriteParam eventWriteParam) throws InterruptedException, ExecutionException, TimeoutException {
        eventWriteParam.setEventType(String.valueOf(CodeConst.getEventTypeQZ(eventWriteParam.getEventType())));
        List<EventWriteParam> list = new ArrayList<>();
        list.add(eventWriteParam);
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
        String token = stringRedisTemplate.opsForValue().get(qztoken);
        headers.add("token", token);
        HttpEntity<List<EventWriteParam>> requestEntity = new HttpEntity<>(list, headers);
        return CompletableFuture.supplyAsync(() -> restTemplate.postForObject(url, requestEntity, WriteResultObj.class)).get(timeout, TimeUnit.MILLISECONDS);
    }

    private void dealResult(WriteResultObj writeResultObj, Traffalarmrecord traffalarmrecord) {
        Traffalarmrecord condition = new Traffalarmrecord();
        condition.setRecordid(traffalarmrecord.getRecordid());
        String message = writeResultObj.getMessage();
        boolean successFlag = writeResultObj.getStatus() == ResponseEnum.SUCCESS.getCode();
        condition.setPushdesc(message);
        /* 失败但是因为数据已存在 */
        if (!successFlag && StringUtils.isNotBlank(message) && message.contains(CONTAINS_EXIST)) {
            condition.setPushstatus(1);
            traffAlarmRecordMapper.updatePushEvent(condition);
            return;
        }
        /* 成功 */

        if (successFlag) {
            condition.setPushstatus(0);
            traffAlarmRecordMapper.updatePushEvent(condition);
            return;
        }
        /* 其他失败 */
        condition.setPushstatus(1);
        traffAlarmRecordMapper.updatePushEvent(condition);
    }

    public ResultObj updateAndSendEvents(List<Traffalarmrecord> traffalarmrecord) {
        int error = 0;
        int success = 0;
        for (Traffalarmrecord ta : traffalarmrecord) {
            ResultObj resultObj = updateAndSendEvent(ta);
            String message = resultObj.getMsg();
            boolean successFlag = resultObj.getStatus() == ResponseEnum.SUCCESS.getCode() || (StringUtils.isNotBlank(message) && message.contains(CONTAINS_EXIST));
            /* 成功 */
            if (successFlag) {
                success++;
                continue;
            }
            error++;
        }
        return ResultObj.error(ResponseEnum.SUCCESS.getCode(), "成功" + success + "条|失败" + error + "条");
    }

    public ResultObj updateAndAutoSendEvent(Traffalarmrecord traffalarmrecord) {
        if (recordtype.equals("1")) {
            //过滤掉工程类的
            if(traffalarmrecord.getRecordtype().equalsIgnoreCase("roadworks") || traffalarmrecord.getRecordtype().equalsIgnoreCase("roadworks_out_of_line"))
                return ResultObj.ok();

        }
        if (!StringEnum.ONE.getValue().equals(checkPushEnable)) {
            /* 自动推送开关是否开启 */
            return ResultObj.ok("记录recordid:" + traffalarmrecord.getRecordid() + ",推送开关[未启用],将不会推送");
        }
        return updateAndSendEvent(traffalarmrecord);
    }
}
