package com.fuyuanshen.global.mqtt.rule.hby100j;

import com.alibaba.fastjson2.JSONObject;
import com.fuyuanshen.common.core.constant.GlobalConstants;
import com.fuyuanshen.common.core.utils.StringUtils;
import com.fuyuanshen.common.json.utils.JsonUtils;
import com.fuyuanshen.common.redis.utils.RedisUtils;
import com.fuyuanshen.equipment.utils.map.GetAddressFromLatUtil;
import com.fuyuanshen.equipment.utils.map.LngLonUtil;
import com.fuyuanshen.global.mqtt.base.NewMqttMessageRule;
import com.fuyuanshen.global.mqtt.base.NewMqttRuleContext;
import com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants;
import com.fuyuanshen.global.mqtt.rule.hby100j.domin.FunctionType3LocationReport;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.LinkedHashMap;
import java.util.Map;

import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVICE_KEY_PREFIX;
import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVICE_LOCATION_KEY_PREFIX;

/**
 * 获取设备位置信息（设备下发返回响应数据、设备定时主动上报）
 */
@Slf4j
@Component
public class FuncType3Location implements NewMqttMessageRule {

    @Override
    public String getCommandType() {
        return "HBY100_3";
    }

    @Override
    public void execute(NewMqttRuleContext context) {
        log.info("HBY100J获取设备位置信息，消息负载：{}", context.getPayloadDict());

        try {
            String redisKey = GlobalConstants.GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + 
                             context.getDeviceImei() + ":location";
            
            Map<String, Object> payloadDict = context.getPayloadDict();
            if (payloadDict != null) {
//                RedisUtils.setCacheObject(redisKey, JSONObject.toJSONString(payloadDict));
                String jsonString = JSONObject.toJSONString(payloadDict);
                FunctionType3LocationReport data = JSONObject.parseObject(jsonString, FunctionType3LocationReport.class);
                FunctionType3LocationReport.Data data1 = data.getData();
                if (data1 != null) {
                    Double latitude = data1.getLatitude();
                    Double longitude = data1.getLongitude();
                    asyncSendLocationToRedisWithFuture(context.getDeviceImei(), latitude.toString(), longitude.toString());
                }
            }
        } catch (Exception e) {
            log.error("HBY100J获取设备位置信息失败", e);
        }
    }

    /** 位置未发生明显变化的距离阈值（米），可通过配置中心动态调整 */
    private final double MOVEMENT_THRESHOLD_METER = 10.0;

    /**
     * 异步发送位置信息到Redis（使用CompletableFuture）
     *
     * @param deviceImei 设备IMEI
     * @param latitude   纬度
     * @param longitude  经度
     */
    public void asyncSendLocationToRedisWithFuture(String deviceImei, String latitude, String longitude) {
        try {
            if (latitude == null || longitude == null) {
                return;
            }
            if (StringUtils.isAnyBlank(deviceImei, latitude, longitude)) {
                log.warn("位置上报参数为空，deviceImei={}", deviceImei);
                return;
            }
            //log.info("位置上报，deviceImei={}, lat={}, lon={}", deviceImei, latitude, longitude);
            // 1. 解析当前上报的经纬度
            Double curLat = parseDoubleSafe(latitude.trim());
            Double curLon = parseDoubleSafe(longitude.trim());
            if (curLat == null || curLon == null) {
                log.warn("经纬度格式错误，直接更新，deviceImei={}, lat={}, lon={}", deviceImei, latitude, longitude);
//                doSaveLocation(deviceImei, latitude, longitude);
                return;
            }

            // 2. 读取 Redis 中缓存的上一次位置
            String redisKey = GlobalConstants.GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + deviceImei + DEVICE_LOCATION_KEY_PREFIX;
            String cachedJson = RedisUtils.getCacheObject(redisKey);

            if (StringUtils.isNotBlank(cachedJson)) {
                com.alibaba.fastjson2.JSONObject cachedObj = com.alibaba.fastjson2.JSONObject.parseObject(cachedJson);
                String cachedWgs84Lat = cachedObj.getString("wgs84_latitude");
                String cachedWgs84Lon = cachedObj.getString("wgs84_longitude");

                Double oldLat = parseDoubleSafe(cachedWgs84Lat);
                Double oldLon = parseDoubleSafe(cachedWgs84Lon);

                if (oldLat != null && oldLon != null) {
                    double distance = haversine(oldLat, oldLon, curLat, curLon);
                    if (distance <= MOVEMENT_THRESHOLD_METER) {
                        log.info("位置未发生明显变化（{}米 <= {}米），不更新 Redis，deviceImei={}, lat={}, lon={}",
                                distance, MOVEMENT_THRESHOLD_METER, deviceImei, latitude, longitude);
                        return;
                    }
                }
            }
//                String[] latArr = latitude.split("\\.");
//                String[] lonArr = longitude.split("\\.");
//                // 将位置信息存储到Redis中
//            String redisKey = GlobalConstants.GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + deviceImei + DEVICE_LOCATION_KEY_PREFIX;
//                String redisObj = RedisUtils.getCacheObject(redisKey);
//                JSONObject jsonOBj = JSONObject.parseObject(redisObj);
//                if(jsonOBj != null){
//                    String str1 = latArr[0] +"."+ latArr[1].substring(0,4);
//                    String str2 = lonArr[0] +"."+ lonArr[1].substring(0,4);
//
//                    String cacheLatitude = jsonOBj.getString("wgs84_latitude");
//                    String cacheLongitude = jsonOBj.getString("wgs84_longitude");
//                    String[] latArr1 = cacheLatitude.split("\\.");
//                    String[] lonArr1 = cacheLongitude.split("\\.");
//
//                    String cacheStr1 = latArr1[0] +"."+ latArr1[1].substring(0,4);
//                    String cacheStr2 = lonArr1[0] +"."+ lonArr1[1].substring(0,4);
//                    if(str1.equals(cacheStr1) && str2.equals(cacheStr2)){
//                        log.info("位置信息未发生变化: device={}, lat={}, lon={}", deviceImei, latitude, longitude);
//                        return;
//                    }
//                }

            // 构造位置信息对象
            Map<String, Object> locationInfo = new LinkedHashMap<>();
            double[] doubles = LngLonUtil.gps84_To_Gcj02(Double.parseDouble(latitude), Double.parseDouble(longitude));
            locationInfo.put("deviceImei", deviceImei);
            locationInfo.put("latitude", doubles[0]);
            locationInfo.put("longitude", doubles[1]);
            locationInfo.put("wgs84_latitude", latitude);
            locationInfo.put("wgs84_longitude", longitude);


            String address = GetAddressFromLatUtil.getAdd(String.valueOf(doubles[1]), String.valueOf(doubles[0]));
            locationInfo.put("address", address);
            locationInfo.put("timestamp", System.currentTimeMillis());


            String locationJson = JsonUtils.toJsonString(locationInfo);

            // 存储到Redis
            RedisUtils.setCacheObject(redisKey, locationJson);

            // 存储到一个列表中，保留历史位置信息
//                String locationHistoryKey = GlobalConstants.GLOBAL_REDIS_KEY+DeviceRedisKeyConstants.DEVICE_LOCATION_HISTORY_KEY_PREFIX + deviceImei;
//                RedisUtils.addCacheList(locationHistoryKey, locationJson);
//                RedisUtils.expire(locationHistoryKey, Duration.ofDays(90));
            storeDeviceTrajectoryWithSortedSet(deviceImei, locationJson);
            log.info("位置信息已异步发送到Redis: device={}, lat={}, lon={}", deviceImei, latitude, longitude);
        } catch (Exception e) {
            log.error("异步发送位置信息到Redis时出错: device={}, error={}", deviceImei, e.getMessage(), e);
        }
    }
    /** 安全解析 double，解析失败返回 null */
    private Double parseDoubleSafe(String str) {
        if (StringUtils.isBlank(str)) return null;
        try {
            return Double.parseDouble(str.trim());
        } catch (NumberFormatException e) {
            return null;
        }
    }
    /** Haversine 公式计算两点球面距离（米） */
    private double haversine(double lat1, double lon1, double lat2, double lon2) {
        double dLat = Math.toRadians(lat2 - lat1);
        double dLon = Math.toRadians(lon2 - lon1);
        double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
                Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2)) *
                        Math.sin(dLon / 2) * Math.sin(dLon / 2);
        double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
        /** 地球平均半径（米） */
        double EARTH_RADIUS = 6371_393.0;
        return EARTH_RADIUS * c;
    }

    /**
     * 存储设备30天历史轨迹到Redis (使用Sorted Set)
     */
    public void storeDeviceTrajectoryWithSortedSet(String deviceImei, String locationJson) {
        try {
            String trajectoryKey = GlobalConstants.GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + deviceImei + DeviceRedisKeyConstants.DEVICE_LOCATION_HISTORY_KEY_PREFIX;
//            String trajectoryKey = "device:trajectory:zset:" + deviceImei;
//            String locationJson = JsonUtils.toJsonString(locationInfo);
            long timestamp = System.currentTimeMillis();

            // 添加到Sorted Set，使用时间戳作为score
            RedisUtils.zAdd(trajectoryKey, locationJson, timestamp);

//            // 设置30天过期时间
//            RedisUtils.expire(trajectoryKey, Duration.ofDays(30));

            // 清理30天前的数据（冗余保护）
            long thirtyDaysAgo = System.currentTimeMillis() - (7L * 24 * 60 * 60 * 1000);
            RedisUtils.zRemoveRangeByScore(trajectoryKey, 0, thirtyDaysAgo);
        } catch (Exception e) {
            log.error("存储设备轨迹到Redis(ZSet)失败: device={}, error={}", deviceImei, e.getMessage(), e);
        }
    }
}
