package com.aiotagro.cattletrade.business.service;

import com.aiotagro.cattletrade.business.dto.yingyan.YingyanStayPoint;
import com.aiotagro.cattletrade.business.dto.yingyan.YingyanTrackPoint;
import com.aiotagro.common.core.constant.BaiduYingyanConstants;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import java.time.Duration;
import java.util.Date;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 百度鹰眼 API 封装
 */
@Service
public class BaiduYingyanService {

    private static final Logger logger = LoggerFactory.getLogger(BaiduYingyanService.class);

    private final RestTemplate restTemplate;
    private final ObjectMapper objectMapper;

    public BaiduYingyanService(ObjectMapper objectMapper) {
        this.objectMapper = objectMapper;
        this.restTemplate = buildRestTemplate();
    }

    /**
     * 确保终端存在（幂等）
     * 返回值：true-终端存在或创建成功，false-创建失败（终端不存在且创建失败）
     */
    public boolean ensureEntity(String entityName) {
        if (StringUtils.isBlank(entityName)) {
            logger.warn("ensureEntity 失败：终端名称为空");
            return false;
        }
        
        // ✅ 去除空格，确保格式一致
        String cleanEntityName = entityName.trim();
        
        // ✅ 验证 entityName 不是 "entity" 字符串
        if ("entity".equals(cleanEntityName) || "entity_name".equals(cleanEntityName)) {
            logger.error("ensureEntity 失败：entityName 参数错误，值为 '{}'，这可能是参数传递错误", cleanEntityName);
            return false;
        }

        try {
            MultiValueMap<String, String> form = baseForm();
            form.add("entity_name", cleanEntityName);
            // entity_desc 为非必填项，且命名规则限制：只支持中文、英文字母、下划线、连字符、数字
            // 为避免参数错误，不传递 entity_desc 参数

            logger.debug("确保终端存在 - entity={}, service_id={}", cleanEntityName, BaiduYingyanConstants.SERVICE_ID);
            JsonNode result = postForm("/entity/add", form);
            int status = result.path("status").asInt(-1);
            String message = result.path("message").asText();
            
            // ✅ 修复：status=0（创建成功）、3005（终端已存在）、3006（其他成功状态）都视为成功
            if (status == 0) {
                logger.info("✅ 鹰眼终端创建成功, entityName={}, service_id={}", cleanEntityName, BaiduYingyanConstants.SERVICE_ID);
                return true;
            } else if (status == 3005) {
                // ✅ 终端已存在，这是正常情况，视为成功
                logger.info("✅ 鹰眼终端已存在, entityName={}, service_id={}, message={}", 
                    cleanEntityName, BaiduYingyanConstants.SERVICE_ID, message);
                return true;
            } else if (status == 3006) {
                logger.info("✅ 鹰眼终端操作成功, entityName={}, service_id={}, status={}", 
                    cleanEntityName, BaiduYingyanConstants.SERVICE_ID, status);
                return true;
            }
            
            // 其他状态码视为失败
            logger.warn("❌ 鹰眼创建终端失败, entityName={}, service_id={}, status={}, message={}",
                cleanEntityName, BaiduYingyanConstants.SERVICE_ID, status, message);
        } catch (Exception e) {
            logger.error("❌ 鹰眼创建终端异常, entityName={}", cleanEntityName, e);
        }
        return false;
    }

    /**
     * 推送单条轨迹点
     */
    public boolean pushTrackPoint(String entityName, double latitude, double longitude, long locTime) {
        if (StringUtils.isBlank(entityName)) {
            logger.warn("鹰眼上传轨迹失败：终端名称为空");
            return false;
        }
        
        // ✅ 验证经纬度有效性
        if (latitude == 0 && longitude == 0) {
            logger.warn("鹰眼上传轨迹失败：经纬度无效 (0,0), entity={}", entityName);
            return false;
        }
        if (latitude < -90 || latitude > 90 || longitude < -180 || longitude > 180) {
            logger.warn("鹰眼上传轨迹失败：经纬度超出有效范围, entity={}, lat={}, lon={}", 
                entityName, latitude, longitude);
            return false;
        }
        
        try {
            MultiValueMap<String, String> form = baseForm();
            form.add("entity_name", entityName);
            form.add("latitude", String.valueOf(latitude));
            form.add("longitude", String.valueOf(longitude));
            form.add("loc_time", String.valueOf(locTime));
            form.add("coord_type_input", "wgs84");

            logger.debug("鹰眼上传轨迹点 - entity={}, lat={}, lon={}, locTime={}", 
                entityName, latitude, longitude, locTime);
            
            JsonNode result = postForm("/track/addpoint", form);
            int status = result.path("status").asInt(-1);
            String message = result.path("message").asText();
            
            if (status == 0) {
                logger.debug("鹰眼上传轨迹成功 - entity={}, lat={}, lon={}", 
                    entityName, latitude, longitude);
                return true;
            }
            
            // ✅ 详细记录失败原因
            logger.warn("鹰眼上传轨迹失败 - entity={}, status={}, message={}, lat={}, lon={}, locTime={}", 
                entityName, status, message, latitude, longitude, locTime);
            
            // 如果是常见错误，记录更详细的信息
            if (status == 3001) {
                logger.error("鹰眼上传轨迹失败：参数错误，请检查经纬度和时间格式");
            } else if (status == 3002) {
                logger.error("鹰眼上传轨迹失败：服务不存在或未启用");
            } else if (status == 3003) {
                logger.error("鹰眼上传轨迹失败：终端不存在");
            } else if (status == 3004) {
                logger.error("鹰眼上传轨迹失败：轨迹点时间格式错误");
            }
            
        } catch (Exception e) {
            logger.error("鹰眼上传轨迹异常 - entity={}, lat={}, lon={}, locTime={}", 
                entityName, latitude, longitude, locTime, e);
        }
        return false;
    }

    /**
     * 批量推送轨迹点（使用 /track/addpoints 接口）
     * @param entityName 终端名称
     * @param points 轨迹点列表
     * @return 成功上传的轨迹点数量
     */
    public int pushTrackPoints(String entityName, List<YingyanTrackPoint> points) {
        if (StringUtils.isBlank(entityName)) {
            logger.warn("鹰眼批量上传轨迹失败：终端名称为空");
            return 0;
        }
        if (points == null || points.isEmpty()) {
            logger.warn("鹰眼批量上传轨迹失败：轨迹点列表为空, entity={}", entityName);
            return 0;
        }

        try {
            // ✅ 确保终端存在
            if (!ensureEntity(entityName)) {
                logger.warn("鹰眼批量上传轨迹失败：终端不存在或创建失败, entity={}", entityName);
                return 0;
            }

            // ✅ 构建 point_list JSON 数组字符串
            List<Map<String, Object>> pointList = new ArrayList<>();
            for (YingyanTrackPoint point : points) {
                // 验证经纬度有效性
                if (point.getLatitude() == 0 && point.getLongitude() == 0) {
                    logger.warn("鹰眼批量上传：跳过无效轨迹点 (0,0), entity={}", entityName);
                    continue;
                }
                if (point.getLatitude() < -90 || point.getLatitude() > 90 || 
                    point.getLongitude() < -180 || point.getLongitude() > 180) {
                    logger.warn("鹰眼批量上传：跳过超出范围的轨迹点, entity={}, lat={}, lon={}", 
                        entityName, point.getLatitude(), point.getLongitude());
                    continue;
                }

                Map<String, Object> pointMap = new HashMap<>();
                pointMap.put("entity_name", entityName);
                pointMap.put("coord_type_input", "wgs84"); // 根据数据源调整坐标类型
                pointMap.put("loc_time", point.getLocTime());
                pointMap.put("longitude", point.getLongitude());
                pointMap.put("latitude", point.getLatitude());
                if (point.getSpeed() != null && point.getSpeed() > 0) {
                    pointMap.put("speed", point.getSpeed());
                }
                if (point.getDirection() != null) {
                    pointMap.put("direction", point.getDirection());
                }
                pointList.add(pointMap);
            }

            if (pointList.isEmpty()) {
                logger.warn("鹰眼批量上传：过滤后无有效轨迹点, entity={}, 原始数量={}", entityName, points.size());
                return 0;
            }

            // ✅ 将 pointList 转换为 JSON 字符串
            String pointListJson = objectMapper.writeValueAsString(pointList);

            // ✅ 构建 POST 请求参数
            MultiValueMap<String, String> form = baseForm();
            form.add("point_list", pointListJson);

            logger.info("鹰眼批量上传轨迹点 - entity={}, 轨迹点数量={}", entityName, pointList.size());

            JsonNode result = postForm("/track/addpoints", form);
            int status = result.path("status").asInt(-1);
            String message = result.path("message").asText();

            if (status == 0) {
                // ✅ 批量上传成功，返回成功数量
                int successCount = pointList.size();
                logger.info("鹰眼批量上传轨迹成功 - entity={}, 成功数量={}", entityName, successCount);
                return successCount;
            }

            // ✅ 详细记录失败原因
            logger.warn("鹰眼批量上传轨迹失败 - entity={}, status={}, message={}, 轨迹点数量={}", 
                entityName, status, message, pointList.size());

            // 如果是常见错误，记录更详细的信息
            if (status == 3001) {
                logger.error("鹰眼批量上传轨迹失败：参数错误，请检查轨迹点格式");
            } else if (status == 3002) {
                logger.error("鹰眼批量上传轨迹失败：服务不存在或未启用");
            } else if (status == 3003) {
                logger.error("鹰眼批量上传轨迹失败：终端不存在");
            } else if (status == 3004) {
                logger.error("鹰眼批量上传轨迹失败：轨迹点时间格式错误");
            }

        } catch (Exception e) {
            logger.error("鹰眼批量上传轨迹异常 - entity={}, 轨迹点数量={}", entityName, points.size(), e);
        }
        return 0;
    }

    /**
     * 查询轨迹（单次查询，限制24小时内）
     */
    public List<YingyanTrackPoint> queryTrack(String entityName, long startTime, long endTime) {
        if (StringUtils.isBlank(entityName)) {
            return Collections.emptyList();
        }
        
        // ✅ 查询前再次确保终端存在，避免查询时终端不存在
        if (!ensureEntity(entityName)) {
            logger.warn("查询轨迹前终端不存在或创建失败，无法查询 - entity={}", entityName);
            return Collections.emptyList();
        }
        
        try {
            // ✅ 去除空格，确保格式一致
            String cleanEntityName = entityName.trim();
            
            Map<String, Object> params = new HashMap<>();
            params.put("entity_name", cleanEntityName);
            // ✅ 所有参数统一为 String 类型
            params.put("start_time", String.valueOf(startTime));
            params.put("end_time", String.valueOf(endTime));
            params.put("is_processed", "1");
            // ✅ 根据用户测试成功的 URL，添加 process_option 参数
            // 格式：need_denoise=1,need_vacuate=1,need_mapmatch=0
            params.put("process_option", "need_denoise=1,need_vacuate=1,need_mapmatch=0");
            // ✅ 可选参数，根据官方文档添加
            params.put("coord_type_output", "bd09ll");
            params.put("page_size", "5000");
            params.put("page_index", "1");
            params.put("sort_type", "asc");

            logger.debug("查询轨迹 - entity={}, startTime={} ({}), endTime={} ({})", 
                entityName, startTime, new Date(startTime * 1000), endTime, new Date(endTime * 1000));

            JsonNode result = get("/track/gettrack", params);
            int status = result.path("status").asInt(-1);
            String message = result.path("message").asText();
            
            logger.info("鹰眼查询轨迹响应 - entity={}, status={}, message={}, startTime={}, endTime={}",
                entityName, status, message, new Date(startTime * 1000), new Date(endTime * 1000));
            
            if (!isSuccess(result)) {
                // ✅ status=3003 可能是"终端不存在"或"指定时间范围内无轨迹数据"
                // 如果终端确实存在（通过 ensureEntity 确认），则可能是时间范围内无数据
                if (status == 3003) {
                    logger.info("鹰眼查询轨迹：指定时间范围内可能无轨迹数据, entity={}, startTime={}, endTime={}, message={}",
                        entityName, new Date(startTime * 1000), new Date(endTime * 1000), message);
                } else {
                    logger.warn("鹰眼查询轨迹失败, entity={}, status={}, message={}, startTime={}, endTime={}, raw={}",
                        entityName, status, message, new Date(startTime * 1000), new Date(endTime * 1000), result.toString());
                }
                return Collections.emptyList();
            }

            // 文档返回结构存在两种形式：直接 points 字段 或 track.points
            JsonNode pointsNode = result.path("points");
            if (pointsNode == null || pointsNode.isMissingNode()) {
                pointsNode = result.path("track").path("points");
            }
            if (pointsNode == null || pointsNode.isMissingNode()) {
                logger.warn("鹰眼响应缺少 points 字段，entity={}, raw={}", entityName, result.toString());
                return Collections.emptyList();
            }
            if (!pointsNode.isArray()) {
                logger.warn("鹰眼响应 points 字段不是数组，entity={}, raw={}", entityName, result.toString());
                return Collections.emptyList();
            }
            if (pointsNode.size() == 0) {
                logger.warn("鹰眼返回0个轨迹点，entity={}, startTime={}, endTime={}, raw={}",
                    entityName, new Date(startTime * 1000), new Date(endTime * 1000), result.toString());
                return Collections.emptyList();
            }

            logger.info("鹰眼返回轨迹点数量：entity={}, size={}", entityName, pointsNode.size());
            List<YingyanTrackPoint> points = new ArrayList<>(pointsNode.size());
            pointsNode.forEach(node -> {
                if (!node.hasNonNull("latitude") || !node.hasNonNull("longitude")) {
                    return;
                }
                YingyanTrackPoint point = new YingyanTrackPoint();
                point.setLatitude(node.path("latitude").asDouble());
                point.setLongitude(node.path("longitude").asDouble());
                point.setLocTime(node.path("loc_time").asLong());
                if (node.has("speed")) {
                    point.setSpeed(node.path("speed").asDouble());
                }
                if (node.has("direction")) {
                    point.setDirection(node.path("direction").asDouble());
                }
                points.add(point);
            });
            return points;
        } catch (Exception e) {
            logger.error("鹰眼查询轨迹异常, entity={}", entityName, e);
            return Collections.emptyList();
        }
    }

    /**
     * 查询最新轨迹点（实时位置）
     */
    public YingyanTrackPoint queryLatestPoint(String entityName) {
        if (StringUtils.isBlank(entityName)) {
            logger.warn("查询最新轨迹点失败：终端名称为空");
            return null;
        }

        try {
            // ✅ 查询前再次确保终端存在
            if (!ensureEntity(entityName)) {
                logger.warn("查询最新轨迹点前终端不存在或创建失败，entity={}", entityName);
                return null;
            }

            Map<String, Object> params = new HashMap<>();
            params.put("entity_name", entityName);
            params.put("coord_type_output", "bd09ll");
            // ✅ 根据官方文档，process_option 为可选参数，暂时移除避免格式错误
            // params.put("process_option", "denoise_grade=1,radius_threshold=20,need_mapmatch=1,transport_mode=driving");

            JsonNode result = get("/track/getlatestpoint", params);
            if (!isSuccess(result)) {
                int status = result.path("status").asInt(-1);
                String message = result.path("message").asText();
                logger.warn("鹰眼查询最新轨迹点失败, entity={}, status={}, message={}", entityName, status, message);
                return null;
            }

            JsonNode pointNode = result.path("latest_point");
            if (pointNode == null || pointNode.isMissingNode() || pointNode.isNull()) {
                logger.warn("鹰眼查询最新轨迹点成功但无数据, entity={}", entityName);
                return null;
            }

            if (!pointNode.hasNonNull("latitude") || !pointNode.hasNonNull("longitude")) {
                logger.warn("鹰眼最新轨迹点缺少经纬度, entity={}", entityName);
                return null;
            }

            double latitude = pointNode.path("latitude").asDouble();
            double longitude = pointNode.path("longitude").asDouble();
            if (latitude == 0 && longitude == 0) {
                logger.warn("鹰眼最新轨迹点经纬度无效 (0,0), entity={}", entityName);
                return null;
            }

            YingyanTrackPoint latestPoint = new YingyanTrackPoint();
            latestPoint.setLatitude(latitude);
            latestPoint.setLongitude(longitude);
            latestPoint.setLocTime(pointNode.path("loc_time").asLong(0));

            if (pointNode.has("speed") && !pointNode.path("speed").isNull()) {
                latestPoint.setSpeed(pointNode.path("speed").asDouble());
            }
            if (pointNode.has("direction") && !pointNode.path("direction").isNull()) {
                latestPoint.setDirection(pointNode.path("direction").asDouble());
            }

            logger.debug("查询最新轨迹点成功 - entity={}, lat={}, lon={}, locTime={}",
                entityName, latitude, longitude, latestPoint.getLocTime());
            return latestPoint;
        } catch (Exception e) {
            logger.error("鹰眼查询最新轨迹点异常, entity={}", entityName, e);
            return null;
        }
    }

    /**
     * 分段查询轨迹（支持超过24小时的查询）
     * 按照24小时为间隔分段查询，然后拼接结果
     * 
     * @param entityName 终端名称
     * @param startTime 开始时间（秒级时间戳）
     * @param endTime 结束时间（秒级时间戳，不能超过当前时间）
     * @return 拼接后的轨迹点列表，按时间排序
     */
    public List<YingyanTrackPoint> queryTrackSegmented(String entityName, long startTime, long endTime) {
        if (StringUtils.isBlank(entityName)) {
            return Collections.emptyList();
        }
        
        // ✅ 首先确保终端存在
        if (!ensureEntity(entityName)) {
            logger.warn("查询轨迹前终端不存在或创建失败，无法查询 - entity={}", entityName);
            return Collections.emptyList();
        }
        
        // 验证时间范围
        long currentTime = System.currentTimeMillis() / 1000;
        if (endTime > currentTime) {
            logger.warn("结束时间不能超过当前时间，自动调整为当前时间。entity={}, endTime={}, currentTime={}", 
                entityName, endTime, currentTime);
            endTime = currentTime;
        }
        
        if (startTime >= endTime) {
            logger.warn("开始时间不能大于等于结束时间。entity={}, startTime={}, endTime={}", 
                entityName, startTime, endTime);
            return Collections.emptyList();
        }
        
        // 计算时间差（秒）
        long timeDiff = endTime - startTime;
        // 24小时 = 86400秒
        final long SEGMENT_INTERVAL = 86400L;
        
        // 如果时间差小于等于24小时，直接查询
        if (timeDiff <= SEGMENT_INTERVAL) {
            logger.debug("时间范围在24小时内，直接查询。entity={}, startTime={}, endTime={}, diff={}秒", 
                entityName, startTime, endTime, timeDiff);
            return queryTrack(entityName, startTime, endTime);
        }
        
        // 需要分段查询
        logger.info("开始分段查询轨迹 - entity={}, startTime={}, endTime={}, 总时长={}小时", 
            entityName, startTime, endTime, timeDiff / 3600);
        
        List<YingyanTrackPoint> allPoints = new ArrayList<>();
        long segmentStart = startTime;
        int segmentIndex = 1;
        
        while (segmentStart < endTime) {
            // 计算当前段的结束时间（不超过endTime，且不超过24小时）
            long segmentEnd = Math.min(segmentStart + SEGMENT_INTERVAL, endTime);
            
            logger.debug("查询第{}段轨迹 - entity={}, segmentStart={}, segmentEnd={}, 时长={}小时", 
                segmentIndex, entityName, segmentStart, segmentEnd, (segmentEnd - segmentStart) / 3600);
            
            try {
                // ✅ 在查询前确保终端存在（每段都检查，因为可能在某些时间段终端还未创建）
                if (!ensureEntity(entityName)) {
                    logger.warn("第{}段查询前终端不存在或创建失败，跳过该段 - entity={}", segmentIndex, entityName);
                    segmentStart = segmentEnd;
                    segmentIndex++;
                    continue;
                }
                
                List<YingyanTrackPoint> segmentPoints = queryTrack(entityName, segmentStart, segmentEnd);
                if (!segmentPoints.isEmpty()) {
                    allPoints.addAll(segmentPoints);
                    logger.debug("第{}段查询成功，获得{}个轨迹点", segmentIndex, segmentPoints.size());
                } else {
                    logger.debug("第{}段无轨迹点", segmentIndex);
                }
            } catch (Exception e) {
                logger.error("第{}段轨迹查询异常 - entity={}, segmentStart={}, segmentEnd={}", 
                    segmentIndex, entityName, segmentStart, segmentEnd, e);
                // 继续查询下一段，不中断
            }
            
            // 移动到下一段（下一段的开始时间 = 当前段的结束时间）
            segmentStart = segmentEnd;
            segmentIndex++;
            
            // 避免无限循环
            if (segmentIndex > 100) {
                logger.error("分段查询超过100段，可能存在逻辑错误，停止查询。entity={}", entityName);
                break;
            }
        }
        
        // 按时间排序并去重（基于locTime）
        if (!allPoints.isEmpty()) {
            // 按时间排序
            allPoints.sort(Comparator.comparingLong(YingyanTrackPoint::getLocTime));
            
            // 去重：相同时间戳的轨迹点只保留一个
            List<YingyanTrackPoint> uniquePoints = new ArrayList<>();
            long lastLocTime = -1;
            for (YingyanTrackPoint point : allPoints) {
                if (point.getLocTime() != lastLocTime) {
                    uniquePoints.add(point);
                    lastLocTime = point.getLocTime();
                }
            }
            
            logger.info("分段查询完成 - entity={}, 总段数={}, 原始轨迹点数={}, 去重后轨迹点数={}", 
                entityName, segmentIndex - 1, allPoints.size(), uniquePoints.size());
            
            return uniquePoints;
        }
        
        logger.warn("分段查询未获得任何轨迹点 - entity={}, startTime={}, endTime={}", 
            entityName, startTime, endTime);
        return Collections.emptyList();
    }

    /**
     * 查询停留点（单次查询，限制24小时内）
     */
    public List<YingyanStayPoint> queryStayPoints(String entityName, long startTime, long endTime, int stayTimeSeconds) {
        if (StringUtils.isBlank(entityName)) {
            logger.warn("查询停留点失败：终端名称为空");
            return Collections.emptyList();
        }
        
        // ✅ 验证 entityName 不是 "entity" 字符串
        if ("entity".equals(entityName) || "entity_name".equals(entityName)) {
            logger.error("查询停留点失败：entityName 参数错误，值为 '{}'，这可能是参数传递错误", entityName);
            return Collections.emptyList();
        }
        
        try {
            Map<String, Object> params = new HashMap<>();
            params.put("entity_name", entityName);
            // ✅ 所有参数统一为 String 类型
            params.put("start_time", String.valueOf(startTime));
            params.put("end_time", String.valueOf(endTime));
            params.put("stay_time", String.valueOf(stayTimeSeconds));
            params.put("coord_type_output", "bd09ll");

            logger.debug("查询停留点 - entity={}, startTime={} ({}), endTime={} ({}), stayTimeSeconds={}", 
                entityName, startTime, new Date(startTime * 1000), endTime, new Date(endTime * 1000), stayTimeSeconds);

            JsonNode result = get("/analysis/staypoint", params);
            int status = result.path("status").asInt(-1);
            String message = result.path("message").asText();
            
            if (!isSuccess(result)) {
                // ✅ status=3003 可能是"终端不存在"或"指定时间范围内无停留点数据"
                // 如果终端确实存在（通过 ensureEntity 确认），则可能是时间范围内无数据
                if (status == 3003) {
                    logger.debug("鹰眼查询停留点：指定时间范围内可能无停留点数据, entity={}, startTime={}, endTime={}, message={}",
                        entityName, new Date(startTime * 1000), new Date(endTime * 1000), message);
                } else {
                    logger.warn("鹰眼查询停留点失败, entity={}, status={}, message={}, startTime={}, endTime={}",
                        entityName, status, message, new Date(startTime * 1000), new Date(endTime * 1000));
                }
                return Collections.emptyList();
            }

            JsonNode stayNode = result.path("stay_points");
            if (stayNode == null || !stayNode.isArray() || stayNode.size() == 0) {
                return Collections.emptyList();
            }

            List<YingyanStayPoint> stayPoints = new ArrayList<>(stayNode.size());
            stayNode.forEach(node -> {
                if (!node.hasNonNull("latitude") || !node.hasNonNull("longitude")) {
                    return;
                }
                YingyanStayPoint stayPoint = new YingyanStayPoint();
                stayPoint.setLatitude(node.path("latitude").asDouble());
                stayPoint.setLongitude(node.path("longitude").asDouble());
                stayPoint.setStartTime(node.path("start_time").asLong());
                stayPoint.setEndTime(node.path("end_time").asLong());
                stayPoint.setDuration(node.path("duration").asLong());
                stayPoints.add(stayPoint);
            });
            return stayPoints;
        } catch (Exception e) {
            logger.error("鹰眼查询停留点异常, entity={}", entityName, e);
            return Collections.emptyList();
        }
    }

    /**
     * 分段查询停留点（支持超过24小时的查询）
     * 按照24小时为间隔分段查询，然后拼接结果
     * 
     * @param entityName 终端名称
     * @param startTime 开始时间（秒级时间戳）
     * @param endTime 结束时间（秒级时间戳，不能超过当前时间）
     * @param stayTimeSeconds 停留时间阈值（秒）
     * @return 拼接后的停留点列表，按开始时间排序
     */
    public List<YingyanStayPoint> queryStayPointsSegmented(String entityName, long startTime, long endTime, int stayTimeSeconds) {
        if (StringUtils.isBlank(entityName)) {
            return Collections.emptyList();
        }
        
        // ✅ 首先确保终端存在
        if (!ensureEntity(entityName)) {
            logger.warn("查询停留点前终端不存在或创建失败，无法查询 - entity={}", entityName);
            return Collections.emptyList();
        }
        
        // 验证时间范围
        long currentTime = System.currentTimeMillis() / 1000;
        if (endTime > currentTime) {
            logger.warn("结束时间不能超过当前时间，自动调整为当前时间。entity={}, endTime={}, currentTime={}", 
                entityName, endTime, currentTime);
            endTime = currentTime;
        }
        
        if (startTime >= endTime) {
            logger.warn("开始时间不能大于等于结束时间。entity={}, startTime={}, endTime={}", 
                entityName, startTime, endTime);
            return Collections.emptyList();
        }
        
        // 计算时间差（秒）
        long timeDiff = endTime - startTime;
        // 24小时 = 86400秒
        final long SEGMENT_INTERVAL = 86400L;
        
        // 如果时间差小于等于24小时，直接查询
        if (timeDiff <= SEGMENT_INTERVAL) {
            logger.debug("时间范围在24小时内，直接查询停留点。entity={}, startTime={}, endTime={}, diff={}秒", 
                entityName, startTime, endTime, timeDiff);
            return queryStayPoints(entityName, startTime, endTime, stayTimeSeconds);
        }
        
        // 需要分段查询
        logger.info("开始分段查询停留点 - entity={}, startTime={}, endTime={}, 总时长={}小时", 
            entityName, startTime, endTime, timeDiff / 3600);
        
        List<YingyanStayPoint> allStayPoints = new ArrayList<>();
        long segmentStart = startTime;
        int segmentIndex = 1;
        
        while (segmentStart < endTime) {
            // 计算当前段的结束时间（不超过endTime，且不超过24小时）
            long segmentEnd = Math.min(segmentStart + SEGMENT_INTERVAL, endTime);
            
            logger.debug("查询第{}段停留点 - entity={}, segmentStart={}, segmentEnd={}, 时长={}小时", 
                segmentIndex, entityName, segmentStart, segmentEnd, (segmentEnd - segmentStart) / 3600);
            
            try {
                // ✅ 在查询前确保终端存在（每段都检查，因为可能在某些时间段终端还未创建）
                if (!ensureEntity(entityName)) {
                    logger.warn("第{}段查询前终端不存在或创建失败，跳过该段 - entity={}", segmentIndex, entityName);
                    segmentStart = segmentEnd;
                    segmentIndex++;
                    continue;
                }
                
                List<YingyanStayPoint> segmentStayPoints = queryStayPoints(entityName, segmentStart, segmentEnd, stayTimeSeconds);
                if (!segmentStayPoints.isEmpty()) {
                    allStayPoints.addAll(segmentStayPoints);
                    logger.debug("第{}段查询成功，获得{}个停留点", segmentIndex, segmentStayPoints.size());
                } else {
                    logger.debug("第{}段无停留点", segmentIndex);
                }
            } catch (Exception e) {
                logger.error("第{}段停留点查询异常 - entity={}, segmentStart={}, segmentEnd={}", 
                    segmentIndex, entityName, segmentStart, segmentEnd, e);
                // 继续查询下一段，不中断
            }
            
            // 移动到下一段（下一段的开始时间 = 当前段的结束时间）
            segmentStart = segmentEnd;
            segmentIndex++;
            
            // 避免无限循环
            if (segmentIndex > 100) {
                logger.error("分段查询超过100段，可能存在逻辑错误，停止查询。entity={}", entityName);
                break;
            }
        }
        
        // 按开始时间排序并去重（基于startTime）
        if (!allStayPoints.isEmpty()) {
            // 按开始时间排序
            allStayPoints.sort(Comparator.comparingLong(YingyanStayPoint::getStartTime));
            
            // 去重：相同开始时间的停留点只保留一个
            List<YingyanStayPoint> uniqueStayPoints = new ArrayList<>();
            long lastStartTime = -1;
            for (YingyanStayPoint stayPoint : allStayPoints) {
                if (stayPoint.getStartTime() != lastStartTime) {
                    uniqueStayPoints.add(stayPoint);
                    lastStartTime = stayPoint.getStartTime();
                }
            }
            
            logger.info("分段查询停留点完成 - entity={}, 总段数={}, 原始停留点数={}, 去重后停留点数={}", 
                entityName, segmentIndex - 1, allStayPoints.size(), uniqueStayPoints.size());
            
            return uniqueStayPoints;
        }
        
        logger.warn("分段查询未获得任何停留点 - entity={}, startTime={}, endTime={}", 
            entityName, startTime, endTime);
        return Collections.emptyList();
    }

    private JsonNode postForm(String path, MultiValueMap<String, String> form) throws Exception {
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));

        HttpEntity<MultiValueMap<String, String>> httpEntity = new HttpEntity<>(form, headers);
        ResponseEntity<String> response = restTemplate.postForEntity(buildUrl(path), httpEntity, String.class);
        return parseBody(response.getBody());
    }

    private JsonNode get(String path, Map<String, Object> params) throws Exception {
        // ✅ 手动构建 URL，所有参数都不进行 URL 编码（与用户测试成功的 URL 格式一致）
        StringBuilder urlBuilder = new StringBuilder(buildUrl(path));
        urlBuilder.append("?ak=").append(BaiduYingyanConstants.AK);
        urlBuilder.append("&service_id=").append(BaiduYingyanConstants.SERVICE_ID);
        
        if (params != null) {
            for (Map.Entry<String, Object> entry : params.entrySet()) {
                String key = entry.getKey();
                Object value = entry.getValue();
                if (value != null) {
                    // ✅ 验证参数名和值，避免参数传递错误
                    if ("entity_name".equals(key) && ("entity".equals(value) || "entity_name".equals(value))) {
                        logger.error("参数传递错误：entity_name 的值不能是 '{}'，这可能是参数名和值混淆了", value);
                        throw new IllegalArgumentException("entity_name 参数值错误: " + value);
                    }
                    
                    // ✅ 所有参数都不进行 URL 编码，直接拼接（与用户测试成功的 URL 格式一致）
                    urlBuilder.append("&").append(key).append("=").append(value.toString());
                }
            }
        }
        
        String requestUrl = urlBuilder.toString();
        String maskedUrl = requestUrl.replaceAll("ak=[^&]+", "ak=***").replaceAll("service_id=[^&]+", "service_id=***");
        Object entityNameParam = params != null ? params.get("entity_name") : "N/A";
        logger.info("百度鹰眼API请求 - path={}, entity_name={}, service_id={}, url={}", 
            path, entityNameParam, BaiduYingyanConstants.SERVICE_ID, maskedUrl);
        
        // ✅ 记录实际请求 URL（用于调试，生产环境可关闭）
        logger.debug("百度鹰眼API实际请求URL - {}", requestUrl.replaceAll("ak=[^&]+", "ak=***"));
        
        String response = restTemplate.getForObject(requestUrl, String.class);
        return parseBody(response);
    }

    private JsonNode parseBody(String body) throws Exception {
        if (StringUtils.isBlank(body)) {
            return objectMapper.createObjectNode();
        }
        return objectMapper.readTree(body);
    }

    private boolean isSuccess(JsonNode node) {
        if (node == null) {
            return false;
        }
        int status = node.path("status").asInt(-1);
        return status == 0;
    }

    private MultiValueMap<String, String> baseForm() {
        MultiValueMap<String, String> form = new LinkedMultiValueMap<>();
        form.add("ak", BaiduYingyanConstants.AK);
        form.add("service_id", String.valueOf(BaiduYingyanConstants.SERVICE_ID));
        return form;
    }

    private RestTemplate buildRestTemplate() {
        org.springframework.http.client.SimpleClientHttpRequestFactory factory =
            new org.springframework.http.client.SimpleClientHttpRequestFactory();
        factory.setConnectTimeout((int) Duration.ofSeconds(10).toMillis());
        factory.setReadTimeout((int) Duration.ofSeconds(30).toMillis());
        return new RestTemplate(factory);
    }

    private String buildUrl(String path) {
        if (StringUtils.isBlank(path)) {
            return BaiduYingyanConstants.BASE_URL;
        }
        if (path.startsWith("http")) {
            return path;
        }
        if (!path.startsWith("/")) {
            path = "/" + path;
        }
        return BaiduYingyanConstants.BASE_URL + path;
    }
}

