package com.ruoyi.web.controller.robot;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.mqtt.service.MqttSendService;
import com.ruoyi.mqtt.util.MqttTopicUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * 地图管理Controller
 * 提供地图列表、缩略图、路网数据、点云等API
 * 数据源：LD导航系统后端（http://192.168.0.102:8086）
 */
@Api(tags = "地图管理")
@RestController
@RequestMapping("/robot/map")
public class RobotMapController {

    @Value("${ld-nav.url:http://192.168.0.102:8086}")
    private String ldNavUrl;

    @Autowired
    private MqttSendService mqttSendService;

    @Autowired
    private RedisCache redisCache;

    private final RestTemplate restTemplate = new RestTemplate();


    // ==================== 导入导出API ====================

    @ApiOperation("压缩导出地图")
    @PostMapping("/export/compress")
    public AjaxResult compressMapExport(@RequestBody Map<String, Object> params) {
        try {
            String url = ldNavUrl + "/v1/map/export/compress";
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);
            HttpEntity<Map<String, Object>> request = new HttpEntity<>(params, headers);
            
            ResponseEntity<String> response = restTemplate.postForEntity(url, request, String.class);
            
            if (response.getStatusCode() == HttpStatus.OK) {
                return AjaxResult.success("压缩成功", JSON.parse(response.getBody()));
            }
            return AjaxResult.error("压缩失败");
        } catch (Exception e) {
            return AjaxResult.error("压缩异常: " + e.getMessage());
        }
    }

    @ApiOperation("下载地图导出包")
    @GetMapping("/export")
    public ResponseEntity<byte[]> downloadMapExport(
            @ApiParam("地图名称") @RequestParam("map") String mapName
    ) {
        try {
            String url = ldNavUrl + "/v1/map/export?map=" + mapName;
            ResponseEntity<byte[]> response = restTemplate.getForEntity(url, byte[].class);
            
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
            headers.setContentDisposition(ContentDisposition.builder("attachment")
                    .filename(mapName + ".zip")
                    .build());
            
            return new ResponseEntity<>(response.getBody(), headers, HttpStatus.OK);
        } catch (Exception e) {
            return ResponseEntity.notFound().build();
        }
    }

    @ApiOperation("导入地图")
    @PostMapping("/import")
    public AjaxResult importMap(
            @ApiParam("地图文件") @RequestParam("file") org.springframework.web.multipart.MultipartFile file
    ) {
        try {
            String url = ldNavUrl + "/v1/map/import";
            
            MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
            body.add("filedata", file.getResource());
            
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.MULTIPART_FORM_DATA);
            
            HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(body, headers);
            
            ResponseEntity<String> response = restTemplate.postForEntity(url, requestEntity, String.class);
            
            if (response.getStatusCode() == HttpStatus.OK) {
                return AjaxResult.success("导入成功", JSON.parse(response.getBody()));
            }
            return AjaxResult.error("导入失败");
        } catch (Exception e) {
            return AjaxResult.error("导入异常: " + e.getMessage());
        }
    }

    // ==================== 路网数据API ====================

    @ApiOperation("获取路网GeoJSON数据")
    @GetMapping("/roadmap/geojson")
    public AjaxResult getRoadMapGeoJson(
            @ApiParam("地图名称") @RequestParam("map") String mapName
    ) {
        try {
            String cacheKey = "ld:roadmap:" + mapName;
            Object cached = redisCache.getCacheObject(cacheKey);
            if (cached != null) {
                return AjaxResult.success("获取成功(缓存)", cached);
            }

            String url = ldNavUrl + "/v1/roadmap/geojson?map=" + mapName;
            ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
            
            if (response.getStatusCode() == HttpStatus.OK) {
                JSONObject geojson = JSON.parseObject(response.getBody());
                // 缓存10分钟
                redisCache.setCacheObject(cacheKey, geojson, 10, TimeUnit.MINUTES);
                return AjaxResult.success("获取成功", geojson);
            }
            return AjaxResult.error("获取路网数据失败");
        } catch (Exception e) {
            return AjaxResult.error("获取路网数据异常: " + e.getMessage());
        }
    }

    @ApiOperation("保存路网GeoJSON数据")
    @PostMapping("/roadmap/geojson")
    public AjaxResult saveRoadMapGeoJson(@RequestBody JSONObject geoJsonData) {
        try {
            String mapName = geoJsonData.getString("map");
            if (mapName == null) {
                return AjaxResult.error("缺少地图名称");
            }

            String url = ldNavUrl + "/v1/roadmap/geojson";
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);
            HttpEntity<JSONObject> request = new HttpEntity<>(geoJsonData, headers);
            
            ResponseEntity<String> response = restTemplate.postForEntity(url, request, String.class);
            
            if (response.getStatusCode() == HttpStatus.OK) {
                // 清除路网缓存
                redisCache.deleteObject("ld:roadmap:" + mapName);
                return AjaxResult.success("保存成功");
            }
            return AjaxResult.error("保存失败");
        } catch (Exception e) {
            return AjaxResult.error("保存异常: " + e.getMessage());
        }
    }

    // ==================== 任务路线API ====================

    @ApiOperation("获取任务路线列表")
    @GetMapping("/path/list")
    public AjaxResult listPath(
            @ApiParam("地图名称") @RequestParam("map") String mapName
    ) {
        try {
            String url = ldNavUrl + "/v1/path/list?map=" + mapName;
            ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
            
            if (response.getStatusCode() == HttpStatus.OK) {
                return AjaxResult.success("获取成功", JSON.parse(response.getBody()));
            }
            return AjaxResult.error("获取路线列表失败");
        } catch (Exception e) {
            return AjaxResult.error("获取路线列表异常: " + e.getMessage());
        }
    }

    @ApiOperation("获取任务路线详情")
    @GetMapping("/path")
    public AjaxResult getPath(
            @ApiParam("地图名称") @RequestParam("map") String mapName,
            @ApiParam("路线名称") @RequestParam("path") String pathName
    ) {
        try {
            String url = ldNavUrl + "/v1/path?map=" + mapName + "&path=" + pathName;
            ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
            
            if (response.getStatusCode() == HttpStatus.OK) {
                return AjaxResult.success("获取成功", JSON.parse(response.getBody()));
            }
            return AjaxResult.error("获取路线详情失败");
        } catch (Exception e) {
            return AjaxResult.error("获取路线详情异常: " + e.getMessage());
        }
    }

    @ApiOperation("添加任务路线")
    @PostMapping("/path")
    public AjaxResult addPath(@RequestBody Map<String, Object> params) {
        try {
            String url = ldNavUrl + "/v1/path";
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);
            HttpEntity<Map<String, Object>> request = new HttpEntity<>(params, headers);
            
            ResponseEntity<String> response = restTemplate.postForEntity(url, request, String.class);
            
            if (response.getStatusCode() == HttpStatus.OK) {
                return AjaxResult.success("添加成功");
            }
            return AjaxResult.error("添加失败");
        } catch (Exception e) {
            return AjaxResult.error("添加异常: " + e.getMessage());
        }
    }

    @ApiOperation("删除任务路线")
    @DeleteMapping("/path")
    public AjaxResult deletePath(@RequestBody Map<String, String> params) {
        try {
            String map = params.get("map");
            String path = params.get("path");
            
            String url = ldNavUrl + "/v1/path?map=" + map + "&path=" + path;
            HttpHeaders headers = new HttpHeaders();
            HttpEntity<String> request = new HttpEntity<>(headers);
            
            ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.DELETE, request, String.class);
            
            if (response.getStatusCode() == HttpStatus.OK) {
                return AjaxResult.success("删除成功");
            }
            return AjaxResult.error("删除失败");
        } catch (Exception e) {
            return AjaxResult.error("删除异常: " + e.getMessage());
        }
    }

    // ==================== 标定API ====================

    @ApiOperation("获取标定历史")
    @GetMapping("/calibration/history")
    public AjaxResult getCalibrationHistory(
            @ApiParam("地图名称") @RequestParam("map") String mapName
    ) {
        try {
            String url = ldNavUrl + "/v1/map/file/" + mapName + "/shapefile/calibration.json";
            ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
            
            if (response.getStatusCode() == HttpStatus.OK) {
                return AjaxResult.success("获取成功", JSON.parse(response.getBody()));
            }
            return AjaxResult.error("获取标定历史失败");
        } catch (Exception e) {
            return AjaxResult.error("获取标定历史异常: " + e.getMessage());
        }
    }

    // ==================== VSLAM API ====================

    @ApiOperation("获取VSLAM统计信息")
    @GetMapping("/vslam/statistics")
    public AjaxResult getVSlamStatistics(
            @ApiParam("地图名称") @RequestParam("map") String mapName
    ) {
        try {
            String url = ldNavUrl + "/v1/vslam/statistics?map=" + mapName;
            ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
            
            if (response.getStatusCode() == HttpStatus.OK) {
                return AjaxResult.success("获取成功", JSON.parse(response.getBody()));
            }
            return AjaxResult.error("获取VSLAM统计信息失败");
        } catch (Exception e) {
            return AjaxResult.error("获取VSLAM统计信息异常: " + e.getMessage());
        }
    }

    @ApiOperation("获取关键帧点云")
    @GetMapping("/vslam/keyframe/cloud")
    public ResponseEntity<byte[]> getKeyframeCloud(
            @ApiParam("地图名称") @RequestParam("map") String mapName,
            @ApiParam("关键帧索引") @RequestParam("idx") int idx
    ) {
        try {
            String url = ldNavUrl + "/v1/vslam/keyframe/cloud?map=" + mapName + "&idx=" + idx;
            ResponseEntity<byte[]> response = restTemplate.getForEntity(url, byte[].class);
            return ResponseEntity.ok()
                    .headers(headers -> headers.setContentType(MediaType.APPLICATION_OCTET_STREAM))
                    .body(response.getBody());
        } catch (Exception e) {
            return ResponseEntity.notFound().build();
        }
    }

    @ApiOperation("获取关键帧变换矩阵")
    @GetMapping("/vslam/keyframe/trans")
    public ResponseEntity<byte[]> getKeyframeTrans(
            @ApiParam("地图名称") @RequestParam("map") String mapName,
            @ApiParam("关键帧索引") @RequestParam("idx") int idx
    ) {
        try {
            String url = ldNavUrl + "/v1/vslam/keyframe/trans?map=" + mapName + "&idx=" + idx;
            ResponseEntity<byte[]> response = restTemplate.getForEntity(url, byte[].class);
            return ResponseEntity.ok()
                    .headers(headers -> headers.setContentType(MediaType.APPLICATION_OCTET_STREAM))
                    .body(response.getBody());
        } catch (Exception e) {
            return ResponseEntity.notFound().build();
        }
    }

    @ApiOperation("获取闭环详情")
    @GetMapping("/vslam/closure/details")
    public AjaxResult getClosureDetails(
            @ApiParam("地图名称") @RequestParam("map") String mapName,
            @ApiParam("闭环索引") @RequestParam("idx") int idx
    ) {
        try {
            String url = ldNavUrl + "/v1/vslam/closure/details?map=" + mapName + "&idx=" + idx;
            ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
            
            if (response.getStatusCode() == HttpStatus.OK) {
                return AjaxResult.success("获取成功", JSON.parse(response.getBody()));
            }
            return AjaxResult.error("获取闭环详情失败");
        } catch (Exception e) {
            return AjaxResult.error("获取闭环详情异常: " + e.getMessage());
        }
    }

    // ==================== 传感器API ====================

    @ApiOperation("获取点云数据")
    @GetMapping("/sensor/pointcloud")
    public ResponseEntity<byte[]> getPointcloud() {
        try {
            String url = ldNavUrl + "/v1/sensor/pointcloud/3d";
            ResponseEntity<byte[]> response = restTemplate.getForEntity(url, byte[].class);
            return ResponseEntity.ok()
                    .headers(headers -> headers.setContentType(MediaType.APPLICATION_OCTET_STREAM))
                    .body(response.getBody());
        } catch (Exception e) {
            return ResponseEntity.notFound().build();
        }
    }

    // ==================== 地图瓦片API ====================

    @ApiOperation("获取地图配置信息")
    @GetMapping("/tilemap/details")
    public AjaxResult getTilemapDetails(
            @ApiParam("地图名称") @RequestParam("map") String mapName
    ) {
        try {
            String url = ldNavUrl + "/v1/tilemap/details?map=" + mapName;
            ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
            
            if (response.getStatusCode() == HttpStatus.OK) {
                return AjaxResult.success("获取成功", JSON.parse(response.getBody()));
            }
            return AjaxResult.error("获取地图配置失败");
        } catch (Exception e) {
            return AjaxResult.error("获取地图配置异常: " + e.getMessage());
        }
    }

    // ==================== 设备状态API ====================

    @ApiOperation("获取机器人实时位姿(从Redis缓存)")
    @GetMapping("/robot/pose")
    public AjaxResult getRobotPose(
            @ApiParam("设备ID") @RequestParam(required = false) String deviceId
    ) {
        try {
            String cacheKey = "ld:pose:" + (deviceId != null ? deviceId : "default");
            Object cached = redisCache.getCacheObject(cacheKey);
            if (cached != null) {
                return AjaxResult.success("获取成功(实时)", cached);
            }
            return AjaxResult.error("未获取到位姿数据");
        } catch (Exception e) {
            return AjaxResult.error("获取位姿异常: " + e.getMessage());
        }
    }

    @ApiOperation("获取任务实时信息(从Redis缓存)")
    @GetMapping("/robot/task")
    public AjaxResult getTaskRealtimeInfo(
            @ApiParam("设备ID") @RequestParam(required = false) String deviceId
    ) {
        try {
            String cacheKey = "ld:task:realtime:" + (deviceId != null ? deviceId : "default");
            Object cached = redisCache.getCacheObject(cacheKey);
            if (cached != null) {
                return AjaxResult.success("获取成功(实时)", cached);
            }
            return AjaxResult.error("未获取到任务数据");
        } catch (Exception e) {
            return AjaxResult.error("获取任务信息异常: " + e.getMessage());
        }
    }
}
