package org.dromara.knowledge.embedding;

import okhttp3.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.Objects;

@Component
public class HttpEmbeddingService implements EmbeddingService {

    @Value("${ruoyi.ai.embedding.base-url:}")
    private String baseUrl;

    @Value("${ruoyi.ai.embedding.default-model:bge-large-zh}")
    private String defaultModel;

    private final OkHttpClient client = new OkHttpClient();
    private static final int CACHE_MAX = 1024;
    private final java.util.Map<String, double[]> cache = new java.util.LinkedHashMap<>(CACHE_MAX, 0.75f, true) {
        @Override
        protected boolean removeEldestEntry(java.util.Map.Entry<String, double[]> eldest) {
            return size() > CACHE_MAX;
        }
    };

    @Override
    public double[] embed(String text, String modelName) {
        String model = modelName != null && !modelName.isBlank() ? modelName : defaultModel;
        if (baseUrl == null || baseUrl.isBlank()) {
            return mock(text, model);
        }
        try {
            String key = model + "|" + Integer.toHexString(text.hashCode());
            double[] cached = cache.get(key);
            if (cached != null) return cached;
            String payload = "{\"model\":\"" + model + "\",\"input\":\"" + text.replace("\"", "\\\"") + "\"}";
            Request req = new Request.Builder()
                    .url(baseUrl + "/embeddings")
                    .post(RequestBody.create(MediaType.parse("application/json"), payload))
                    .build();
            try (Response resp = client.newCall(req).execute()) {
                String body = Objects.requireNonNull(resp.body()).string();
                String arr = body.replaceAll("[^\\d\\.,-]", "");
                String[] parts = arr.split(",");
                double[] v = new double[parts.length];
                for (int i = 0; i < parts.length; i++) {
                    v[i] = Double.parseDouble(parts[i]);
                }
                cache.put(key, v);
                return v;
            }
        } catch (Exception e) {
            return mock(text, model);
        }
    }

    private double[] mock(String text, String model) {
        int dim = switch (model) {
            case "bge-large-zh" -> 1024;
            case "bge-base-zh" -> 768;
            default -> 768;
        };
        double[] v = new double[dim];
        java.util.Random r = new java.util.Random(text.hashCode());
        for (int i = 0; i < dim; i++) v[i] = r.nextGaussian();
        double norm = 0;
        for (double x : v) norm += x * x;
        norm = Math.sqrt(norm);
        for (int i = 0; i < v.length; i++) v[i] /= norm;
        return v;
    }
}
