package com.ai.trackwalker.service;

import com.ai.trackwalker.config.RailProperties;
import com.ai.trackwalker.model.ModelRuntimeDeploymentService;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import java.time.Duration;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

@Component
public class AiClient {
    private final RailProperties properties;
    private final RestTemplateBuilder restTemplateBuilder;
    private final ModelRuntimeDeploymentService runtimeDeployments;

    public AiClient(
            RailProperties properties,
            RestTemplateBuilder restTemplateBuilder,
            ModelRuntimeDeploymentService runtimeDeployments
    ) {
        this.properties = properties;
        this.restTemplateBuilder = restTemplateBuilder;
        this.runtimeDeployments = runtimeDeployments;
    }

    public List<Map<String, Object>> analyze(Map<String, Object> resource, List<String> scenes) {
        Map<String, List<String>> groupedScenes = new LinkedHashMap<>();
        for (String scene : scenes) {
            groupedScenes.computeIfAbsent(modelGroupForScene(scene), ignored -> new ArrayList<>()).add(scene);
        }
        List<Map<String, Object>> combined = new ArrayList<>();
        groupedScenes.forEach((modelGroup, groupScenes) -> {
            ModelRuntimeDeploymentService.RuntimeRoute route = route(modelGroup);
            Map<String, Object> body = new LinkedHashMap<>();
            body.put("resource", resource);
            body.put("scenes", groupScenes);
            body.put("model_group", modelGroup);
            body.put("model_version", route.modelVersion());
            body.put("parameters", modelParameters(route.config()));
            body.put("deployment_id", route.deploymentId());
            combined.addAll(call(route, route.inferencePath(), body));
        });
        return combined;
    }

    public List<Map<String, Object>> runModelTest(
            String modelGroup,
            String modelVersion,
            Map<String, Object> resource,
            Map<String, Object> parameters,
            List<String> scenes
    ) {
        ModelRuntimeDeploymentService.RuntimeRoute route = route(modelGroup);
        Map<String, Object> body = new LinkedHashMap<>();
        body.put("model_group", modelGroup);
        body.put("model_version", modelVersion);
        body.put("resource", resource);
        body.put("parameters", parameters == null ? Map.of() : parameters);
        body.put("scenes", scenes == null ? List.of() : scenes);
        body.put("deployment_id", route.deploymentId());
        return call(route, route.testPath(), body);
    }

    public Map<String, Object> runtimeStatus() {
        Map<String, Object> result = new LinkedHashMap<>();
        result.put("vision", callRuntimeStatus(properties.getAi().getVisionUrl()));
        result.put("spatial", callRuntimeStatus(properties.getAi().getPointcloudUrl()));
        result.put("active_deployments", runtimeDeployments.activeDeployments());
        return result;
    }

    @SuppressWarnings("unchecked")
    private List<Map<String, Object>> call(
            ModelRuntimeDeploymentService.RuntimeRoute route,
            String path,
            Map<String, Object> body
    ) {
        Map<String, Object> response = client(route.requestTimeoutSeconds())
                .postForObject(route.serviceUrl() + path, body, Map.class);
        if (response == null || !(response.get("results") instanceof List<?> list)) {
            return List.of();
        }
        return (List<Map<String, Object>>) list;
    }

    @SuppressWarnings("unchecked")
    private Map<String, Object> callRuntimeStatus(String baseUrl) {
        try {
            Map<String, Object> response = restTemplateBuilder.build()
                    .getForObject(baseUrl + "/api/v1/runtime", Map.class);
            return response == null ? Map.of("status", "unavailable") : response;
        } catch (Exception e) {
            return Map.of("status", "unavailable", "error", e.getClass().getSimpleName() + ": " + e.getMessage());
        }
    }

    private RestTemplate client(int timeoutSeconds) {
        int bounded = Math.max(1, Math.min(3600, timeoutSeconds));
        return restTemplateBuilder
                .setConnectTimeout(Duration.ofSeconds(Math.min(10, bounded)))
                .setReadTimeout(Duration.ofSeconds(bounded))
                .build();
    }

    private ModelRuntimeDeploymentService.RuntimeRoute route(String modelGroup) {
        return runtimeDeployments.activeRoute(modelGroup).orElseGet(() -> fallbackRoute(modelGroup));
    }

    private ModelRuntimeDeploymentService.RuntimeRoute fallbackRoute(String modelGroup) {
        boolean spatial = "pointcloud-analyzer".equals(modelGroup) || "change-detector".equals(modelGroup);
        return new ModelRuntimeDeploymentService.RuntimeRoute(
                "environment-fallback",
                "环境变量兼容路由",
                spatial ? properties.getAi().getPointcloudUrl() : properties.getAi().getVisionUrl(),
                spatial ? "/api/v1/pointcloud/analyze" : "/api/v1/inference/detect",
                spatial ? "/api/v1/pointcloud/test" : "/api/v1/inference/test",
                "/api/v1/runtime",
                "",
                "v1.0.0",
                120,
                Map.of()
        );
    }

    @SuppressWarnings("unchecked")
    private Map<String, Object> modelParameters(Map<String, Object> config) {
        Object parameters = config.get("parameters");
        return parameters instanceof Map<?, ?> map ? (Map<String, Object>) map : Map.of();
    }

    private String modelGroupForScene(String scene) {
        if (scene == null) {
            return "vision-detector";
        }
        if (scene.contains("发热")) {
            return "thermal-analyzer";
        }
        if (scene.equals("防洪点精密监测") || scene.equals("危树侵限")) {
            return "pointcloud-analyzer";
        }
        if (scene.equals("塔吊") || scene.equals("彩钢板清理")) {
            return "change-detector";
        }
        if (List.of("深基坑隐患", "违规堆土", "落石", "滑坡预警", "裂缝识别", "水毁核查", "沟渠疏通", "围墙隐患")
                .contains(scene)) {
            return "vision-segmenter";
        }
        return "vision-detector";
    }
}
