package com.ai.trackwalker.uavaccess.flighthub;

import com.ai.trackwalker.uavaccess.common.Jsons;
import com.ai.trackwalker.uavaccess.config.UavAccessProperties;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.sql.Timestamp;
import java.time.Instant;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

@Service
public class ConnectionHealthService {
    public static final List<String> CAPABILITIES = List.of(
            "PROJECT_BINDING",
            "DEVICE_TOPOLOGY",
            "WAYLINE_IMPORT",
            "MISSION_PREFLIGHT",
            "MISSION_DISPATCH",
            "MISSION_STATUS_EVENT",
            "TELEMETRY_BRIDGE",
            "MISSION_RECONCILIATION",
            "MISSION_PAUSE_RESUME"
    );

    private final UavAccessProperties properties;
    private final FlightHubOpenApiClient client;
    private final JdbcTemplate jdbc;

    public ConnectionHealthService(
            UavAccessProperties properties,
            FlightHubOpenApiClient client,
            JdbcTemplate jdbc
    ) {
        this.properties = properties;
        this.client = client;
        this.jdbc = jdbc;
    }

    @Transactional
    public Map<String, Object> check(String connectionId) {
        String id = connectionId == null || connectionId.isBlank() ? "flighthub2-default" : connectionId;
        UavAccessProperties.FlightHub config = properties.getFlighthub();
        List<Map<String, Object>> layers = new ArrayList<>();
        List<String> missing = config.missingRequiredConfiguration(false);
        String status;
        Map<String, Object> detail = new LinkedHashMap<>();
        if (!config.isEnabled() || !missing.isEmpty()) {
            status = "CONFIGURATION_REQUIRED";
            layers.add(layer("CONFIGURATION", "BLOCKED", config.isEnabled()
                    ? "Missing: " + String.join(", ", missing)
                    : "FLIGHTHUB_ENABLED=false"));
            layers.add(layer("NETWORK", "NOT_CHECKED", "Configuration must be completed first"));
            detail.put("missing_configuration", missing);
        } else {
            layers.add(layer("CONFIGURATION", "PASSED", "Required connection settings are present"));
            try {
                Map<String, Object> topology = client.get(
                        "/openapi/v2.0/manage/api/v1/projects/" + config.getProjectUuid() + "/topologies",
                        Map.of()
                );
                int topologyCount = topology.get("list") instanceof List<?> list ? list.size() : 0;
                layers.add(layer("AUTHENTICATION", "PASSED", "OpenAPI token accepted"));
                layers.add(layer("PROJECT", "PASSED", "Project topology is readable; groups=" + topologyCount));
                Map<String, Object> sts = client.post(
                        "/openapi/v2.0/storage/api/v1/workspaces/" + config.getProjectUuid() + "/sts",
                        Map.of("specify_path", "integrations/aitrackwalker/health-check")
                );
                String provider = String.valueOf(sts.getOrDefault("provider", "unknown"));
                boolean usableSts = sts.containsKey("bucket") && sts.containsKey("object_key_prefix") && sts.containsKey("credentials");
                layers.add(layer(
                        "OBJECT_STORAGE",
                        usableSts ? "PASSED" : "BLOCKED",
                        "STS provider=" + provider + (usableSts ? "" : "; required fields missing")
                ));
                layers.add(layer(
                        "MQTT_BRIDGE",
                        properties.getMqtt().isEnabled() ? "CONFIGURED" : "DISABLED",
                        properties.getMqtt().isEnabled()
                                ? properties.getMqtt().getBrokerUrl() + " / " + properties.getMqtt().getTopicFilter()
                                : "Enable after Broker and Topic are confirmed"
                ));
                status = usableSts ? "AVAILABLE" : "DEGRADED";
                detail.put("topology_groups", topologyCount);
                detail.put("storage_provider", provider);
            } catch (FlightHubException exception) {
                status = "DEGRADED";
                layers.add(layer(
                        exception.classification(),
                        "BLOCKED",
                        exception.getMessage()
                ));
                detail.put("classification", exception.classification());
                detail.put("vendor_code", exception.vendorCode());
                detail.put("request_id", exception.requestId());
            }
        }
        Map<String, Object> result = new LinkedHashMap<>();
        result.put("status", status);
        result.put("checked_at", Instant.now().toString());
        result.put("vendor", "FLIGHTHUB2");
        result.put("base_url", config.getBaseUrl());
        result.put("organization_uuid", config.getOrganizationUuid());
        result.put("project_uuid", config.getProjectUuid());
        result.put("layers", layers);
        result.put("capabilities", CAPABILITIES);
        result.put("detail", detail);
        upsert(id, status, result);
        return result;
    }

    private void upsert(String id, String status, Map<String, Object> health) {
        Instant now = Instant.now();
        jdbc.update("""
                        insert into access_vendor_connections(
                            id,vendor_code,base_url,organization_uuid,project_uuid,secret_ref,
                            capability_snapshot,status,health_detail,last_checked_at,created_at,updated_at
                        ) values (?,'FLIGHTHUB2',?,?,?,?,?::jsonb,?,?::jsonb,?,?,?)
                        on conflict (id) do update set
                            base_url=excluded.base_url,
                            organization_uuid=excluded.organization_uuid,
                            project_uuid=excluded.project_uuid,
                            capability_snapshot=excluded.capability_snapshot,
                            status=excluded.status,
                            health_detail=excluded.health_detail,
                            last_checked_at=excluded.last_checked_at,
                            updated_at=excluded.updated_at
                        """,
                id,
                properties.getFlighthub().getBaseUrl(),
                properties.getFlighthub().getOrganizationUuid(),
                properties.getFlighthub().getProjectUuid(),
                properties.getFlighthub().getUserTokenFile().isBlank() ? "env:FLIGHTHUB_USER_TOKEN" : "file:mounted-secret",
                Jsons.write(CAPABILITIES),
                status,
                Jsons.write(health),
                Timestamp.from(now),
                Timestamp.from(now),
                Timestamp.from(now)
        );
    }

    private Map<String, Object> layer(String layer, String status, String message) {
        return Map.of("layer", layer, "status", status, "message", message);
    }
}
