package com.yeejoin.equipmanage.listener;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.yeejoin.equipmanage.common.entity.Car;
import com.yeejoin.equipmanage.common.entity.WlCarMileage;
import com.yeejoin.equipmanage.fegin.IotFeign;
import com.yeejoin.equipmanage.service.ICarService;
import com.yeejoin.equipmanage.service.IWlCarMileageService;
import com.yeejoin.equipmanage.thread.ThreadCar;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.typroject.tyboot.component.emq.EmqKeeper;
import org.typroject.tyboot.component.emq.EmqxListener;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

@Component
public class CarIotNewListener extends EmqxListener {
    Logger logger = LoggerFactory.getLogger(CarIotNewListener.class);

    @Autowired
    private IWlCarMileageService iWlCarMileageService;

    @Autowired
    private ICarService iCarService;

    @Autowired
    private IotFeign iotFeign;
    @Value("${mileage.clippingtime:600000}")
    private Long clipping_time;
    private final String GUIDE_KEY = "813684495d9a3981dd2c7694916fe404";

    private final String GUIDE_URL = "https://restapi.amap.com/v3/geocode/regeo?";

    @Autowired
    private EmqKeeper emqkeeper;

    private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    // 用于根据topicId 也就是物联设备id 存储对应的线程来进行计时
    public static final ConcurrentHashMap<String, ThreadCar> deviceInfo = new ConcurrentHashMap();
    public static final ConcurrentHashMap<String, String> deviceLastInfo = new ConcurrentHashMap();

    @Override
    public void processMessage(String topic, MqttMessage message) throws Exception {

        logger.info("----收到物联消息：：topic---------------" + topic);
        logger.info("----收到物联消息：：message---------------" + message);
        String measurement = topic.split("/")[0];
        String deviceName = topic.split("/")[1];
        //根据topic 组装iotCode
        String iotCode = measurement + deviceName;
        //对于收到的消息进行数据转换
        JSONObject jsonObject = JSONObject.parseObject(message.toString());
        //通过消息存电量到扩展字段2
        this.updateEquipBattery(jsonObject, iotCode);
        logger.info("当前设备信息info" + JSON.toJSONString(deviceInfo));
        //判断是否有效坐标
        if (!ObjectUtils.isEmpty(jsonObject.get("FireCar_Longitude")) && !ObjectUtils.isEmpty(jsonObject.get("FireCar_Latitude"))) {
            //判断是否存在未结束进程，如果不存在，则进入判断插入开始节点
            if (iWlCarMileageService.getUncompleteMileagByIotCode(iotCode)) {
                WlCarMileage wlCarMileage = new WlCarMileage();
                wlCarMileage.setIotCode(iotCode);
                wlCarMileage.setDate(new Date());
                // 获取开始坐标
                double startLongitude = jsonObject.getDoubleValue("FireCar_Longitude");
                double startLatitude = jsonObject.getDoubleValue("FireCar_Latitude");
                // String currentTime = "20"+jsonObject.getString("currentTime");
                wlCarMileage.setStartLongitude(startLongitude);
                wlCarMileage.setStartLatitude(startLatitude);
                // Date startTime = UTCToCST();
                //时间值被mysql自动转换
                Date startTime = new Date((jsonObject.getLong("time") / 1000) * 1000);
                wlCarMileage.setStartTime(startTime);
                wlCarMileage.setStartName(getAddress(startLongitude, startLatitude));
                wlCarMileage.setStartSpeed(Double.valueOf(jsonObject.getDoubleValue("FireCar_Speed")).intValue());
                logger.info("新增数据信息如下：：" + JSONObject.toJSONString(wlCarMileage));
                try {
                    iWlCarMileageService.save(wlCarMileage);
                } catch (Exception e) {
                    e.printStackTrace();
                    iWlCarMileageService.save(wlCarMileage);
                }
            }
            this.updateCarLocation(jsonObject, iotCode);
            //如果map中已经存在该设备或者该设备有但是线程已经执行了
            //存储上报上来的经纬度信息
            String coordinate = jsonObject.getString("FireCar_Longitude")+ jsonObject.getString("FireCar_Latitude");
            logger.info("----收到经纬度消息：：coordinate---------------" + coordinate);
            //判断缓存中是否已经存在该设备对应的倒计时线程
            if (!deviceInfo.containsKey(iotCode)) {
                logger.info("topic---------------------" + topic + "开启计时线程");
                ThreadCar threadCar = new ThreadCar(topic, jsonObject, this.iWlCarMileageService, this.iotFeign, this.iCarService, clipping_time);
                deviceInfo.put(iotCode, threadCar);
                threadCar.start();
            }
            //判断缓存中是否已经存在该设备对应的经纬度信息
            if (!deviceLastInfo.containsKey(iotCode)) {
                deviceLastInfo.put(iotCode, coordinate);
            }
            //如果当前时间减去上报时间大小于配置的时间并且之前没包含上报的数据
            logger.info("----收到上次经纬度消息：：coordinate---------------" + deviceLastInfo.get(iotCode));
            //判断本次上报的经纬度信息是否与当前上报的经纬度信息相同
            if ((!deviceLastInfo.get(iotCode).equals(coordinate))) {
                try {
                    //销毁线程后移除
                    deviceInfo.get(iotCode).interrupt();
                    deviceInfo.remove(iotCode);
                } catch (Exception e) {
                    deviceInfo.remove(iotCode);
                }
                logger.info("topic---------------------" + topic + "销毁后，开启计时线程");
                ThreadCar threadCar = new ThreadCar(topic, jsonObject, this.iWlCarMileageService, this.iotFeign, this.iCarService, clipping_time);
                deviceInfo.put(iotCode, threadCar);
                //更新车辆的最新坐标数据
                deviceLastInfo.put(iotCode, coordinate);
                threadCar.start();
            }
        }

    }

    public String getAddress(double longitude, double lantitude) {
        StringBuilder api = new StringBuilder(GUIDE_URL);
        api.append("key=").append(GUIDE_KEY).append("&location=").append(longitude).append(",").append(lantitude).append("&radius=1000").append("&batch=false").append("&extensions=base").append("&roadlevel=0").append("&batch=false");
        StringBuilder res = new StringBuilder();
        BufferedReader in = null;
        try {
            System.out.println(api.toString());
            URL url = new URL(api.toString());
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setDoOutput(true);
            conn.setRequestMethod("POST");
            in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));
            String line;
            while ((line = in.readLine()) != null) {
                res.append(line).append("\n");
            }
            JSONObject object = JSONObject.parseObject(res.toString());
            System.out.println(object);
            JSONObject regeocode = object.getJSONObject("regeocode");
            String address = regeocode.getString("formatted_address");
            if ("[]".equals(address)) {
                logger.info("===============无效坐标:" + longitude + "," + lantitude);
                address = "无效坐标";
            }
            res = new StringBuilder(address);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (in != null) {
                    in.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return res.toString();
    }

    public Date UTCToCST(String UTCStr) throws ParseException {
        Date date = sdf.parse(UTCStr);
        System.out.println("UTC时间: " + date);
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.HOUR, calendar.get(Calendar.HOUR) + 8);
        return calendar.getTime();
    }

    public void updateCarLocation(JSONObject jsonObject, String iotCode) {
        if (jsonObject.containsKey("FireCar_Longitude") && jsonObject.containsKey("FireCar_Latitude")) {
            // 获取开始坐标
            double startLongitude = jsonObject.getDoubleValue("FireCar_Longitude");
            double startLatitude = jsonObject.getDoubleValue("FireCar_Latitude");
            int direction = jsonObject.getIntValue("direction");

            // 地图推送消息
            Car car = iCarService.getOne(new LambdaQueryWrapper<Car>().eq(Car::getIotCode, iotCode));
            if (car != null && startLongitude != 0 && startLatitude != 0) {
                JSONArray sendArr = new JSONArray();
                JSONObject sendObj = new JSONObject();
                sendObj.put("id", String.valueOf(car.getId()));
                sendObj.put("direction", direction);
                sendObj.put("longitude", String.valueOf(startLongitude));
                sendObj.put("latitude", String.valueOf(startLatitude));
                sendObj.put("carNum", car.getCarNum());
                sendObj.put("bizOrgName", car.getBizOrgName());
                sendArr.add(sendObj);
                MqttMessage mqttMessage = new MqttMessage();
                mqttMessage.setPayload(sendArr.toJSONString().getBytes());
                car.setLongitude(startLongitude);
                car.setLatitude(startLatitude);
                iCarService.updateById(car);
                logger.info("-----------推送车辆位置消息到到地图成功--------");
                try {
                    emqkeeper.getMqttClient().publish("car/location", mqttMessage);
                } catch (MqttException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }

    //存储设备电量到扩展字段2
    public void updateEquipBattery(JSONObject jsonObject, String iotCode) {
        Integer power = 0;
        if (jsonObject.containsKey("additionalInformations") && jsonObject.get("additionalInformations") != null) {
            JSONObject jsonObject1 = JSONObject.parseObject(jsonObject.get("additionalInformations").toString());
            if (jsonObject1 != null) {
                JSONObject jsonObject2 = JSONObject.parseObject(jsonObject1.get("additionalInformations").toString());
                if (jsonObject2 != null && jsonObject2.containsKey("power")) {
                    power = jsonObject2.getInteger("power");
                }
            }
        }

        Car car = iCarService.getOne(new LambdaQueryWrapper<Car>().eq(Car::getIotCode, iotCode));
        if (car != null && power != 0) {
            car.setExtra2(power.toString());
            iCarService.updateById(car);
            logger.info(iotCode+"-----------更新车辆设备电池电量成功--------");
        }
    }
}
