package com.ai.trackwalker.uavaccess.wayline;

import com.ai.trackwalker.uavaccess.common.Jsons;
import com.ai.trackwalker.uavaccess.config.UavAccessProperties;
import com.ai.trackwalker.uavaccess.flighthub.FlightHubException;
import com.ai.trackwalker.uavaccess.flighthub.FlightHubOpenApiClient;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.server.ResponseStatusException;

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

import static org.springframework.http.HttpStatus.BAD_REQUEST;
import static org.springframework.http.HttpStatus.NOT_FOUND;

@Service
public class WaylineService {
    private final UavAccessProperties properties;
    private final FlightHubOpenApiClient client;
    private final FlightHubObjectStorage storage;
    private final WpmlKmzCompiler compiler;
    private final JdbcTemplate jdbc;

    public WaylineService(
            UavAccessProperties properties,
            FlightHubOpenApiClient client,
            FlightHubObjectStorage storage,
            WpmlKmzCompiler compiler,
            JdbcTemplate jdbc
    ) {
        this.properties = properties;
        this.client = client;
        this.storage = storage;
        this.compiler = compiler;
        this.jdbc = jdbc;
    }

    @Transactional
    public Map<String, Object> upload(WaylineUploadRequest request) {
        byte[] kmz = decodeOrCompile(request);
        String checksum = Jsons.sha256(kmz);
        List<Map<String, Object>> existing = jdbc.queryForList("""
                select id, vendor_wayline_id, vendor_request_id, object_key, checksum,
                       import_state, import_code, import_detail::text as import_detail
                from route_vendor_artifacts
                where connection_id=? and project_uuid=? and platform_route_version_id=? and checksum=?
                """, request.connectionId(), project(), request.routeVersionId(), checksum);
        if (!existing.isEmpty()) return normalize(existing.get(0));

        String stablePath = "integrations/aitrackwalker/waylines/" + safe(request.routeVersionId()) + "/" + checksum.substring(0, 16);
        Map<String, Object> sts = client.post(
                "/openapi/v2.0/storage/api/v1/workspaces/" + project() + "/sts",
                Map.of("specify_path", stablePath)
        );
        String prefix = required(sts, "object_key_prefix").replaceAll("/+$", "");
        String objectKey = prefix + "/" + safe(request.name()) + "-" + checksum.substring(0, 12) + ".kmz";
        storage.upload(sts, objectKey, kmz, "application/vnd.google-earth.kmz");

        String requestId = UUID.randomUUID().toString();
        Map<String, Object> callback = client.post(
                "/openapi/v2.0/wayline/api/v1/workspaces/" + project() + "/import-callback",
                Map.of(
                        "object_key", objectKey,
                        "name", request.name(),
                        "file_type", 5,
                        "file_source", 2,
                        "request_id", requestId,
                        "timestamp", Instant.now().toEpochMilli()
                )
        );
        String vendorRequestId = text(callback.getOrDefault("request_id", requestId));
        String vendorWaylineId = text(callback.get("uuid"));
        String id = "wayline-artifact-" + UUID.randomUUID();
        Instant now = Instant.now();
        jdbc.update("""
                        insert into route_vendor_artifacts(
                            id,connection_id,project_uuid,platform_route_version_id,vendor_wayline_id,
                            vendor_request_id,object_key,checksum,import_state,import_detail,created_at,updated_at
                        ) values (?,?,?,?,?,?,?,?, 'IMPORTING',?::jsonb,?,?)
                        """,
                id, request.connectionId(), project(), request.routeVersionId(), vendorWaylineId,
                vendorRequestId, objectKey, checksum, Jsons.write(callback),
                Timestamp.from(now), Timestamp.from(now)
        );
        try {
            return refresh(id);
        } catch (FlightHubException exception) {
            return normalize(require(id));
        }
    }

    @Transactional
    public Map<String, Object> refreshByRouteVersion(String connectionId, String routeVersionId) {
        List<String> ids = jdbc.queryForList("""
                select id from route_vendor_artifacts
                where connection_id=? and project_uuid=? and platform_route_version_id=?
                order by created_at desc limit 1
                """, String.class, connectionId, project(), routeVersionId);
        if (ids.isEmpty()) throw new ResponseStatusException(NOT_FOUND, "Wayline artifact not found");
        return refresh(ids.get(0));
    }

    @Transactional
    public Map<String, Object> refresh(String id) {
        Map<String, Object> row = require(id);
        String requestId = text(row.get("vendor_request_id"));
        Map<String, Object> state = client.get(
                "/openapi/v2.0/wayline/api/v1/workspaces/" + project() + "/wayline-import-state",
                Map.of("request_id", requestId)
        );
        int rawState = integer(state.get("state"), 1);
        String normalized = switch (rawState) {
            case 2 -> "IMPORTED";
            case 3 -> "FAILED";
            default -> "IMPORTING";
        };
        jdbc.update("""
                        update route_vendor_artifacts
                        set import_state=?, import_code=?, import_detail=?::jsonb, updated_at=?
                        where id=?
                        """,
                normalized, text(state.get("code")), Jsons.write(state), Timestamp.from(Instant.now()), id
        );
        return normalize(require(id));
    }

    public Map<String, Object> binding(String connectionId, String routeVersionId) {
        List<Map<String, Object>> rows = jdbc.queryForList("""
                select * from route_vendor_artifacts
                where connection_id=? and project_uuid=? and platform_route_version_id=?
                order by created_at desc limit 1
                """, connectionId, project(), routeVersionId);
        if (rows.isEmpty()) throw new ResponseStatusException(NOT_FOUND, "Wayline artifact not found");
        return normalize(rows.get(0));
    }

    private byte[] decodeOrCompile(WaylineUploadRequest request) {
        if (request.kmzBase64() == null || request.kmzBase64().isBlank()) {
            return compiler.compile(request);
        }
        try {
            return Base64.getDecoder().decode(request.kmzBase64());
        } catch (IllegalArgumentException exception) {
            throw new ResponseStatusException(BAD_REQUEST, "kmz_base64 is invalid");
        }
    }

    private Map<String, Object> require(String id) {
        List<Map<String, Object>> rows = jdbc.queryForList(
                "select * from route_vendor_artifacts where id=?",
                id
        );
        if (rows.isEmpty()) throw new ResponseStatusException(NOT_FOUND, "Wayline artifact not found");
        return rows.get(0);
    }

    private Map<String, Object> normalize(Map<String, Object> row) {
        Map<String, Object> result = new LinkedHashMap<>(row);
        Object detail = result.get("import_detail");
        if (detail instanceof String json) result.put("import_detail", Jsons.map(json));
        result.put("vendor_wayline_id", text(result.get("vendor_wayline_id")));
        result.put("vendor_request_id", text(result.get("vendor_request_id")));
        return result;
    }

    private String project() {
        return properties.getFlighthub().getProjectUuid();
    }

    private String safe(String value) {
        String normalized = value == null ? "wayline" : value.replaceAll("[^A-Za-z0-9._-]", "_");
        return normalized.isBlank() ? "wayline" : normalized.substring(0, Math.min(80, normalized.length()));
    }

    private String required(Map<String, Object> values, String key) {
        String value = text(values.get(key));
        if (value.isBlank()) {
            throw new ResponseStatusException(
                    org.springframework.http.HttpStatus.SERVICE_UNAVAILABLE,
                    "FlightHub response missing " + key
            );
        }
        return value;
    }

    private String text(Object value) {
        return value == null ? "" : String.valueOf(value);
    }

    private int integer(Object value, int fallback) {
        if (value instanceof Number number) return number.intValue();
        try {
            return Integer.parseInt(text(value));
        } catch (NumberFormatException ignored) {
            return fallback;
        }
    }
}
