package com.hzjt.controller;

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;

    @Value("${json.resisurl}")
    private String resisjsonvalue;

    @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;

    Long ldir = new Long(180);
    @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) {
        log.info("alarmevent--------------");
        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);


        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) {
        Traffalarmrecord traffAlarmRecord = new Traffalarmrecord();
        traffAlarmRecord.setAreaid(Long.valueOf(trffClientMessage.getDept()));
        traffAlarmRecord.setRecordtype(trffClientMessage.getIncident_type().toLowerCase());
        traffAlarmRecord.setRecordtime(new Date(Long.valueOf(trffClientMessage.getTs())));
        String[] videoIdArr = trffClientMessage.getVideo_id().split("_");
        traffAlarmRecord.setFdid(videoIdArr[0]);
        Integer channelid = Integer.valueOf(videoIdArr[1]) + 1;
        traffAlarmRecord.setChannelid(channelid);

        //判断是否在正检时间内
        int exists = traffAlarmRecordMapper.selectInChecktimeTraffAlarm(traffAlarmRecord);

        log.info("selectInChecktimeTraffAlarm" + exists);
        if (exists > 0) {
            return;
        }

        traffAlarmRecord.setVideourlfrom(trffClientMessage.getVideo_record_url());
        traffAlarmRecord.setCreatetime(new Date());
        traffAlarmRecord.setObjlable(trffClientMessage.getObjLabel());
        traffAlarmRecord.setPushstatus(9);//设置为未推送

        log.info("selectInworkRectifytimeTraffAlarm" + exists);
        if ((traffAlarmRecord.getRecordtype().equalsIgnoreCase("roadworks_out_of_line") || traffAlarmRecord.getRecordtype().equalsIgnoreCase("roadworks"))) {

            //支持对某一个点位报施工事件后 倒推RECTIFYTIME 查看是否是施工事件 一段时间（时间可以配置）之前的停车事件和行人闯入事件矫正为施工事件
            exists = traffAlarmRecordMapper.updateInworkRectifytimeTraffAlarm(traffAlarmRecord);
            //这个事件如果为停车事件或者行人闯入事件时，设置纠偏状态为1
            if (exists > 0) {
                log.info("setRectificationtype=1");
            }

        }

        List<String> imgBase64List = trffClientMessage.getImg_base64();
        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));
        }

        if (StringEnum.ONE.getValue().equals(checkEnable)) {
            /* 9:免审 */
            traffAlarmRecord.setCheckstatus(9);
        }

        int recordid = traffAlarmRecordMapper.selectmax();
        traffAlarmRecord.setRecordid((long) (recordid));
        //发送给前端
        Map map = new HashMap();
        map.put("type", "alarm");
        map.put("data", trffClientMessage);
        map.put("recordid", recordid);
        WebSocket.GroupSending(JsonUtil.beanToString(map));
        traffAlarmRecord.setProcessstatus("0");
        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("send to guangda:HTTP_OK" + obj.toString());
                                    }
                                } else {
                                    ResultObj obj = eventWriteService.updateAndAutoSendEvent(traffAlarmRecord);
                                    log.info("send to guangda HttpURLConnection.HTTP_Fail--->response message:" + obj.toString());
                                }
                            } catch (IOException e) {
                                System.out.println(e.toString());
                                log.error(e.toString());
                                return 0;
                            }
                        }

                    }
                    return 1;
                }, 50, TimeUnit.SECONDS); //等待50秒钟执行


            } else {
                //推送给第三方
                ResultObj obj = eventWriteService.updateAndAutoSendEvent(traffAlarmRecord);
                log.info("send to guangda novideopath --->response message" + obj.toString());

            }

        } catch (Exception e) {
            log.error("alarm fail :" + 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[] sbAndTd = vehicles.getVideo_id().split("_");
            String sbbh = sbAndTd[0];
            int tdbh = Integer.valueOf(sbAndTd[1]) + 1;
            //重置videoid
            vehicles.setVideo_id(sbbh + "_" + tdbh);
            //直接放入表中
            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  直接推送过去
            log.info("fivevehivle");
            //根据连接的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(videoid)) {
                log.info("flv-----");
                flvCacheService.getvalue(videoid, rtsp);
            }
            log.info(stringRedisTemplate.opsForValue().get(videoid));
            JSONObject jsonObject = JSONObject.parseObject(stringRedisTemplate.opsForValue().get(videoid));

            if (null != jsonObject.getJSONArray("play_list") && jsonObject.getJSONArray("play_list").size() > 0) {
                return String.valueOf(jsonObject.getJSONArray("play_list").get(0));
            }

        }
        return "";


    }

    //自动车流量推送
    @PostMapping("/autotraffflow")
    public ResultObj autotraffflow(@RequestBody AutoVehicles vehicles) {

        log.info("autotraffflow"+vehicles.toString());
        if ("TRAFFIC_STATISTICS_VEHICLES".equalsIgnoreCase(vehicles.getType())) {
            String[] sbAndTd = vehicles.getVideo_id().split("_");
            String sbbh = sbAndTd[0];
            int tdbh = Integer.valueOf(sbAndTd[1]) + 1;
            //重置videoid
            vehicles.setVideo_id(sbbh + "_" + tdbh);
            //直接放入表中
            List<AutoVehiclesdetail> vels = vehicles.getObjs();
            int result = 0;

            for (AutoVehiclesdetail 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.getDirection().longValue()<=ldir.longValue()?"1":"2");
                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();
    }

    //车流量推送
    @GetMapping("/test")
    @ResponseBody
    public String test() {

        Long ldir2 = new Long(180);
        String result=ldir2.longValue()<=ldir.longValue()?"2":"1";
        return result;
    }



}
