package com.correx.core.context.compression

import com.correx.core.context.model.ContextEntry

/**
 * Standing block of load-bearing entities (IDs, numbers, paths, protected terms) pulled out
 * of the lossy path entirely, so even the most compressed tier can't drop them (pipeline §2).
 *
 * Correx is event-sourced, so — unlike the plan's `state/factsheet.toml` — this is NOT a
 * persisted file (that would violate invariant #1). It is derived each assembly from the
 * entries being packed and pinned as a single L0 entry the compressor never drops.
 *
 * Staleness/eviction (pipeline §6): facts are taken newest-first (highest ordinal) and capped
 * at [maxFacts], so least-recently-referenced entities age out instead of growing unbounded.
 */
class FactSheet(
    private val tagger: ProtectedSpanTagger,
    private val maxFacts: Int = DEFAULT_MAX_FACTS,
) {

    fun extract(entries: List<ContextEntry>): List<String> {
        val ordered = LinkedHashSet<String>()
        entries.sortedByDescending { it.ordinal }.forEach { entry ->
            tagger.protectedSpans(entry.content).forEach { span ->
                if (ordered.size < maxFacts) ordered += span.trim()
            }
        }
        return ordered.toList()
    }

    fun render(facts: List<String>): String =
        "## Facts (load-bearing — do not contradict or omit)\n" + facts.joinToString(", ")

    fun isEmpty(facts: List<String>): Boolean = facts.isEmpty()

    private companion object {
        const val DEFAULT_MAX_FACTS = 40
    }
}
