package com.hzjt.controller;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.util.concurrent.RateLimiter;
import com.hzjt.domain.*;
import com.hzjt.handler.FileTransferManager;
import com.hzjt.handler.WebSocket;
import com.hzjt.mapper.SbtdspsrMapper;
import com.hzjt.mapper.TraffAlarmRecordMapper;
import com.hzjt.redis.RedisDao;
import com.hzjt.service.*;
import com.hzjt.util.*;
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.web.bind.annotation.*;

import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;


@RestController
@Slf4j
public class TraffController {
    @Autowired
    ImportService importService;

    @Autowired
    WebSocket webSocket;

    private Map<String, RateLimiter> rateLimiterMap;
    private String port;
    private String dept;
    private Integer rate = 10;
    private SbtdspsrMapper sbtdspsrMapper;

    @Autowired
    TraffFlowService traffFlowService;

    @Value("${flv.resisvalue}")
    private String resisvalue;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    RedisDao redisDao;

    @Autowired
    private TraffAlarmRecordMapper traffAlarmRecordMapper;

    @Autowired
    FtpService ftpService;

    @Autowired
    EventWriteService eventWriteService;
    @Value("ftpIp")
    String ftpIp;
    @Value("ftpPort")
    private String ftpPort;
    @Value("ftpUsername")
    private String ftpUsername;
    @Value("ftpPassword")
    private String ftpPassword;
    @Value("${alarmrecord.check.enable}")
    private String checkEnable;


    @Autowired
    FLVCacheService flvCacheService;

//    @Autowired
//    private SimpMessagingTemplate template;


    private static final String TYPE = "TRAFFIC_INCIDENT_ALARM";

    ScheduledExecutorService schedulepool = Executors.newScheduledThreadPool(5); //创

    @Autowired
    public TraffController(
            @Value("${port}") String port,
            @Value("${message.dept}") String dept,
            @Value("${message.rate}") Integer rate, SbtdspsrMapper sbtdspsrMapper) {

        this.port = port;
        this.rate = rate;
        this.dept = dept.substring(0, 5);
        this.sbtdspsrMapper = sbtdspsrMapper;
        rateLimiterMap = new ConcurrentHashMap<>(16);
    }

    @PostMapping("/alarmevent")
    public ResultObj rece(@RequestBody Alarm trffClientMessage) {

        if (!TYPE.equals(trffClientMessage.getType())) {
            return ResultObj.error(ResponseEnum.E_1002.getCode(), "type类型不正确");
        }


        if (trffClientMessage.getImg_urls().isEmpty()) {
            return ResultObj.error(ResponseEnum.E_1004.getCode(), "img_urls值不能为空");
        }
        if (StringUtils.isBlank(trffClientMessage.getIncident_type())) {
            log.info("incident_type值不能为空" + trffClientMessage.toString());
            return ResultObj.error(ResponseEnum.E_1004.getCode(), "incident_type值不能为空");
        }
        String videoId = trffClientMessage.getVideo_id();

        if (StringUtils.isBlank(videoId) || !videoId.contains("_") || videoId.split("_").length != 2) {
            log.info("video_id值异常 值为:" + videoId);
            return ResultObj.error(ResponseEnum.E_1002.getCode(), "video_id值异常 值为:" + videoId);
        }
        /* 限流 */
        if (!getRateLimiter(videoId).tryAcquire()) {
            log.info("[事件推送]->设备" + videoId + "-推送已达到限流限制");
            return ResultObj.error(ResponseEnum.E_9999.getCode(), "设备" + videoId + "请求过于频繁");
        }

        String[] sbAndTd = videoId.split("_");
        String sbbh = sbAndTd[0];
        int tdbh = Integer.valueOf(sbAndTd[1]) + 1;

        List<Sbtdspsr> sbtdspsrs = sbtdspsrMapper.selectBySbbh(sbbh, tdbh);
        if (sbtdspsrs.isEmpty()) {
            log.info("设备为:" + sbbh + ",通道为:" + tdbh + "未录入(备案)");
            return ResultObj.error(ResponseEnum.E_1002.getCode(), "设备为:" + sbbh + ",通道为:" + tdbh + "未录入(备案)");
        }
        String xzbh = sbtdspsrs.get(0).getXzbh();
        if (xzbh.length() != 12) {
            log.info("设备为:" + sbbh + ",通道为:" + tdbh + "配置的行政区划" + xzbh + "不合规");
            return ResultObj.error(ResponseEnum.E_1002.getCode(), "设备为:" + sbbh + ",通道为:" + tdbh + "配置的行政区划不合规");
        }
        //ts  時間轉成正常時間
            trffClientMessage.setDept(xzbh);
            Map map = new HashMap();
            map.put("type", "alarm");
            map.put("data", trffClientMessage);
            WebSocket.GroupSending(JsonUtil.beanToString(map));

        try { // 清空redis中的部分旧数据
//            importService.cleanCache();
            // 将参数result中的部分数据存入redis中，并把格式校验成功的数据发布至对应频道中
//            importService.cacheAndPublish(JsonUtil.beanToString(trffClientMessage));
            sendevent(trffClientMessage);
        } catch (Exception e) {
            log.error("MessageController receive putData error：" + e.toString());
        }
        return ResultObj.ok(trffClientMessage);
    }
public  void sendevent( Alarm trffClientMessage){
    List<String> imgBase64List = trffClientMessage.getImg_base64();

    Traffalarmrecord traffAlarmRecord = new Traffalarmrecord();
    String imgEnumHead = "IMG";
    Ftp ftp = ftpService.reloadFtp();
    for (int i = 0; i < imgBase64List.size(); i++) {
            /* 图片上传 */
        String path = trffClientMessage.getVideo_id() + "/" + DateUtils.formatCurrDayNoSign();
        String fileName = UUIDUtils.createuuid() + ".jpg";
        if (FTPUtil.uploadFile(ftp, path, fileName, imgBase64List.get(i))) {
            TraffAlarmRecordImgEnum.valueOf(imgEnumHead + i).setImg(traffAlarmRecord, FTPUtil.getFtpUrl(ftp) + path + "/" + fileName);
        }
    }
    List<String> imgUrls = trffClientMessage.getImg_urls();
    for (int i = 0; i < imgUrls.size(); i++) {
        TraffAlarmRecordFromImgEnum.valueOf(imgEnumHead + i).setImg(traffAlarmRecord, imgUrls.get(i));
    }
    String[] videoIdArr = trffClientMessage.getVideo_id().split("_");
    String fdid = videoIdArr[0];
    traffAlarmRecord.setFdid(fdid);
    Integer channelid = Integer.valueOf(videoIdArr[1]) + 1;
    traffAlarmRecord.setChannelid(channelid);

    if (StringEnum.ONE.getValue().equals(checkEnable)) {
            /* 9:免审 */
        traffAlarmRecord.setCheckstatus(9);
    }
    int recordid = traffAlarmRecordMapper.selectmax();
    traffAlarmRecord.setRecordid((long)(recordid+1));
    traffAlarmRecord.setProcessstatus("0");
    traffAlarmRecord.setAreaid(Long.valueOf(trffClientMessage.getDept()));
    traffAlarmRecord.setRecordtype(trffClientMessage.getIncident_type().toLowerCase());
    traffAlarmRecord.setVideourlfrom(trffClientMessage.getVideo_record_url());
    traffAlarmRecord.setRecordtime(new Date(Long.valueOf(trffClientMessage.getTs())));
    traffAlarmRecord.setCreatetime(new Date());
    traffAlarmRecord.setObjlable(trffClientMessage.getObjLabel());
    traffAlarmRecord.setPushstatus(9);//设置为未推送

    traffAlarmRecordMapper.inserTraffAlarmRecord(traffAlarmRecord);

    try {
        String basepath = "gstraff/" + traffAlarmRecord.getFdid() + (traffAlarmRecord.getChannelid() < 10 ? "0" + traffAlarmRecord.getChannelid() : traffAlarmRecord.getChannelid()) + "/" + DateUtils.formatCurrDayNoSign();
        Map<String, Object> transferRecordMap = new HashMap<>();
        FileTransferManager.fetchUrlsFromRecord(traffAlarmRecord, transferRecordMap);
        List<TransferResult> results = FileTransferManager.transferFile(transferRecordMap, ftp, basepath);
        log.info("缓存数据上传结果：" + results.toString());
        Traffalarmrecord recordBak = FileTransferManager.traffAlarmRecordUrlUpdate(results);
        traffAlarmRecord.setImg2path(recordBak.getImg2path());
        traffAlarmRecord.setImg3path(recordBak.getImg3path());
        traffAlarmRecord.setImg4path(recordBak.getImg4path());
        traffAlarmRecord.setImg5path(recordBak.getImg5path());
        traffAlarmRecord.setVideopath(recordBak.getVideopath());

        if (traffAlarmRecord != null && traffAlarmRecord.getRecordid() != null) {
            traffAlarmRecordMapper.updateTraffAlarmRecordUrl(traffAlarmRecord);
        }
        //如果监控视频为空，延时加载重新获取
        if(null==recordBak.getVideopath() || "".equalsIgnoreCase(recordBak.getVideopath())) {

            schedulepool.schedule(()->{
                for (String key : transferRecordMap.keySet()) {
                    if (key.equals("videopath")) {
                        final String url = transferRecordMap.get(key).toString();
                        try {
                            HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
                            //延迟连接
                            connection.setReadTimeout(2000);
                            connection.setConnectTimeout(3000);
                            connection.setRequestMethod("GET");
                            String pname = DateUtils.formatCurrDayNoSign() + "_" + recordid + "_0000_" + key.replace("path", "");
                            String fileName = pname + ".mp4";
                            String ftputl = FTPUtil.getFtpUrl(ftp) + basepath + "/" + fileName;
                            if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
                                InputStream inputStream = connection.getInputStream();
                                log.info("url:", url, " --- " + "key:", key);
                                boolean r = FTPUtil.uploadFile(ftp, basepath, fileName, inputStream);
                                if (r) traffAlarmRecord.setVideopath(ftputl);
                                //只更新监控
                                if (traffAlarmRecord != null && traffAlarmRecord.getRecordid() != null) {
                                    traffAlarmRecordMapper.updateTraffAlarmRecordUrl(traffAlarmRecord);

                                    //推送给第三方
                                    ResultObj obj = eventWriteService.updateAndAutoSendEvent(traffAlarmRecord);
                                    log.info("调用接口推送给广达返回信息：" + obj.toString());

                                }
                            }
                        } catch (IOException e) {
                            System.out.println(e.toString());
                            log.error(e.toString());
                            return 0;
                        }
                    }

                }
                return 1;
            },30, TimeUnit.SECONDS); //等待30秒钟执行
        }else {
            //推送给第三方
            ResultObj obj = eventWriteService.updateAndAutoSendEvent(traffAlarmRecord);
            log.info("调用接口推送给广达返回信息：" + obj.toString());

        }

    } catch (Exception e) {
        log.error("解析事件告警数据异常 :" + e.getMessage());
    }
}

    private RateLimiter getRateLimiter(String videoId) {
        RateLimiter rateLimiter;
        if (rateLimiterMap.containsKey(videoId)) {
            rateLimiter = rateLimiterMap.get(videoId);
        } else {
            RateLimiter value = RateLimiter.create(rate);
            rateLimiter = rateLimiterMap.putIfAbsent(videoId, value);
            if (rateLimiter == null) {
                rateLimiter = value;
            }
        }
        return rateLimiter;
    }



    //车流量推送
    @PostMapping("/traffflow")
    public ResultObj traffflow(@RequestBody Vehicles vehicles) {

        if ("TRAFFIC_STATISTICS_VEHICLES".equalsIgnoreCase(vehicles.getType())) {
//            String time=DateUtils.formatDate(new Date(Long.valueOf(vehicles.getTs())));
//            vehicles.setTs(time);
            String[] sbAndTd = vehicles.getVideo_id().split("_");
            String sbbh = sbAndTd[0];
            int tdbh = Integer.valueOf(sbAndTd[1]) + 1;
            //重置videoid
            vehicles.setVideo_id(sbbh+"_"+tdbh);
            //直接放入表中
//            traffFlowService.saveTraffFlow(vehicles);
           List<Vehiclesdetail> vels=vehicles.getObjs()  ;
            int  result=0;
            for(Vehiclesdetail detail : vels){
                Vehicle  v=new Vehicle();
                v.setId(UUID.randomUUID().toString());
                v.setCreate_time (new Date(Long.valueOf(vehicles.getTs())));
                v.setType(detail.getType());
                v.setDirection(detail.getDirection());
                v.setRuleTag(detail.getRuleTag());
                v.setClassification_confidence(detail.getClassification_confidence());
                v.setVideo_id(vehicles.getVideo_id());
                result=traffFlowService.saveTraffFlowDetail(v);


            }
            //查询近五分钟的车流量，当天车流量websocket  直接推送过去

            //根据连接的name ，群发根据videoid  查询的结果
            webSocket.GroupSendingByVideoid(vehicles.getVideo_id());
        }
        return ResultObj.ok();
    }


    //获取自动规则
    @PostMapping("/autoRule")
    public ResultObj autoRule(@RequestBody AutoRule rules) {
        Map map = new HashMap();
        map.put("type", "rule");
        map.put("data", rules);
        webSocket.AppointSending(rules.getVideo_id(),JsonUtil.beanToString(map));
        return ResultObj.ok();
    }
    //获取flv地址
    @GetMapping("/getflv/{videoid}")
    public String  getflv(@PathVariable("videoid") String videoid) {
        //根据id查询对应的rtsp
       String rtsp= traffFlowService.selectSbtddspsrRtspByVideoid(videoid);
            //huode  resid 中值、

        if(null!=rtsp) {
            if( null==stringRedisTemplate.opsForValue().get(resisvalue))
            {
                log.info("flv-----");
                flvCacheService.getvalue();
            }

            JSONArray jsonArr = JSONObject.parseArray(stringRedisTemplate.opsForValue().get(resisvalue));
            log.info("jsonArr" + jsonArr.size());
            for (int i = 0; i < jsonArr.size(); i++) {
                JSONObject jsonObject = jsonArr.getJSONObject(i);

                if (jsonObject.getString("source").equalsIgnoreCase(rtsp)) {
                     if (null != jsonObject.getJSONArray("play_uris") && jsonObject.getJSONArray("play_uris").size() > 3) {
                        return String.valueOf(jsonObject.getJSONArray("play_uris").get(2));

                    }

                }
            }
        }
        return  "";


    }




    //获取自动规则
    @GetMapping("/test")
    public void autoRule() {
        Vehicle  v=new Vehicle();
        v.setId(UUID.randomUUID().toString());
        v.setCreate_time (DateUtils.parseDate("2020-12-10 23:59:00"));
        v.setType("SEDAN1");
        v.setDirection(Long.valueOf("0"));
        v.setRuleTag("1");
        v.setClassification_confidence(Long.valueOf("0"));
        v.setVideo_id("20200603135925971_1");
        traffFlowService.saveTraffFlowDetail(v);
    }


}
