package at.procon.ted.service;

import at.procon.ted.config.TedProcessorProperties;
import at.procon.dip.runtime.condition.ConditionalOnRuntimeMode;
import at.procon.dip.runtime.config.RuntimeMode;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.stream.Collectors;

/**
 * Service for vectorization-related utilities.
 *
 * This service provides helper methods for:
 * - Generating query embeddings for semantic search
 * - Converting float arrays to PostgreSQL vector format
 * - Checking embedding service availability
 *
 * Note: Document vectorization is now handled by VectorizationRoute (Camel-based)
 * with proper transaction management and concurrent processing.
 *
 * @author Martin.Schweitzer@procon.co.at and claude.ai
 */
@Service
@ConditionalOnRuntimeMode(RuntimeMode.LEGACY)
@RequiredArgsConstructor
@Slf4j
public class VectorizationService {

    private final TedProcessorProperties properties;

    /**
     * Generate query embedding with appropriate prefix for e5 model.
     * Used for semantic search queries.
     */
    public float[] generateQueryEmbedding(String query) {
        if (!properties.getVectorization().isEnabled()) {
            throw new IllegalStateException("Vectorization is disabled");
        }

        try {
            String embeddingApiUrl = properties.getVectorization().getApiUrl() + "/embed";
            URL url = URI.create(embeddingApiUrl).toURL();
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("POST");
            conn.setRequestProperty("Content-Type", "application/json");
            conn.setDoOutput(true);
            conn.setConnectTimeout(30000);
            conn.setReadTimeout(60000);

            // Add query prefix for e5 model
            String prefixedQuery = "query: " + query;

            // Send request
            String requestBody = "{\"text\": " + escapeJson(prefixedQuery) + ", \"is_query\": true}";
            try (OutputStream os = conn.getOutputStream()) {
                os.write(requestBody.getBytes(StandardCharsets.UTF_8));
            }

            // Read response
            if (conn.getResponseCode() == 200) {
                try (BufferedReader reader = new BufferedReader(
                        new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8))) {
                    String response = reader.lines().collect(Collectors.joining());
                    return parseEmbeddingJson(response);
                }
            } else {
                throw new RuntimeException("Embedding API returned status: " + conn.getResponseCode());
            }

        } catch (Exception e) {
            throw new RuntimeException("Failed to generate query embedding", e);
        }
    }

    /**
     * Parse JSON response from embedding service.
     * Expected format: {"embedding": [0.1, 0.2, ...], "dimensions": 1024}
     */
    private float[] parseEmbeddingJson(String json) {
        json = json.trim();

        // Check for error response
        if (json.startsWith("{\"error\"")) {
            throw new RuntimeException("Embedding error: " + json);
        }

        // Extract embedding array from response
        // Format: {"embedding": [...], "dimensions": 1024}
        int embeddingStart = json.indexOf("\"embedding\":");
        if (embeddingStart == -1) {
            throw new RuntimeException("Invalid embedding response: " + json);
        }

        int arrayStart = json.indexOf("[", embeddingStart);
        int arrayEnd = json.indexOf("]", arrayStart);
        if (arrayStart == -1 || arrayEnd == -1) {
            throw new RuntimeException("Invalid embedding array in response");
        }

        String arrayContent = json.substring(arrayStart + 1, arrayEnd);
        String[] parts = arrayContent.split(",");
        float[] result = new float[parts.length];
        for (int i = 0; i < parts.length; i++) {
            result[i] = Float.parseFloat(parts[i].trim());
        }
        return result;
    }

    /**
     * Escape string for JSON.
     */
    private String escapeJson(String text) {
        return "\"" + text
                .replace("\\", "\\\\")
                .replace("\"", "\\\"")
                .replace("\n", "\\n")
                .replace("\r", "\\r")
                .replace("\t", "\\t")
                + "\"";
    }

    /**
     * Convert float array to PostgreSQL vector format: [0.1,0.2,0.3]
     * Used by VectorizationProcessorService.
     */
    public String floatArrayToVectorString(float[] embedding) {
        StringBuilder sb = new StringBuilder("[");
        for (int i = 0; i < embedding.length; i++) {
            if (i > 0) sb.append(",");
            sb.append(embedding[i]);
        }
        sb.append("]");
        return sb.toString();
    }

    /**
     * Check if vectorization service is available.
     */
    public boolean isAvailable() {
        return properties.getVectorization().isEnabled() && isHttpApiAvailable();
    }

    /**
     * Check if HTTP embedding API is reachable.
     */
    private boolean isHttpApiAvailable() {
        try {
            String healthUrl = properties.getVectorization().getApiUrl() + "/health";
            URL url = URI.create(healthUrl).toURL();
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("GET");
            conn.setConnectTimeout(5000);
            return conn.getResponseCode() == 200;
        } catch (Exception e) {
            return false;
        }
    }
}
