package com.correx.core.inference

import com.correx.core.context.compression.RelevanceScorer
import kotlin.math.sqrt

/**
 * [RelevanceScorer] backed by an [Embedder]: cosine similarity of each candidate to the current
 * query, rescaled from [-1,1] to [0,1]. Feeds the pipeline's query-conditioned selection — under
 * budget pressure the least query-relevant turns are dropped first, regardless of age (pipeline §6).
 * Embeds the query once, then each candidate; a failed embedding scores 0.5 (neutral) so one bad
 * call doesn't distort the ranking.
 */
class EmbeddingRelevanceScorer(private val embedder: Embedder) : RelevanceScorer {

    override suspend fun score(query: String, candidates: List<String>): List<Double> {
        val q = runCatching { embedder.embed(query) }.getOrNull() ?: return candidates.map { NEUTRAL }
        return candidates.map { c ->
            runCatching { cosine(q, embedder.embed(c)) }.getOrDefault(NEUTRAL)
        }
    }

    private fun cosine(a: FloatArray, b: FloatArray): Double {
        if (a.isEmpty() || b.isEmpty() || a.size != b.size) return NEUTRAL
        var dot = 0.0; var na = 0.0; var nb = 0.0
        for (i in a.indices) { dot += a[i] * b[i]; na += a[i] * a[i]; nb += b[i] * b[i] }
        if (na == 0.0 || nb == 0.0) return NEUTRAL
        val cos = dot / (sqrt(na) * sqrt(nb))
        return ((cos + 1.0) / 2.0).coerceIn(0.0, 1.0)
    }

    private companion object {
        const val NEUTRAL = 0.5
    }
}
