package com.correx.core.tools.compression

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

/**
 * Declarative, config-reachable description of how a tool's output is compressed
 * before entering the context pack. Rules apply in order, line-oriented.
 */
@Serializable
data class OutputCompressionSpec(
    val rules: List<CompressionRule> = emptyList(),
    /** Non-zero exit code -> pass raw output through untouched. */
    val bypassOnError: Boolean = true,
)

/**
 * A single line-oriented compression step. Sealed hierarchy with kotlinx
 * automatic polymorphic serialization (each subtype is @Serializable with a
 * stable @SerialName). NOT an EventPayload — no eventModule registration.
 */
@Serializable
sealed interface CompressionRule {
    /** Drop lines that are empty or whitespace-only. */
    @Serializable
    @SerialName("strip_blank_lines")
    data object StripBlankLines : CompressionRule

    /** Trim leading whitespace from every line. */
    @Serializable
    @SerialName("strip_leading_whitespace")
    data object StripLeadingWhitespace : CompressionRule

    /** Drop every line matching [pattern] (compiled at compressor construction). */
    @Serializable
    @SerialName("drop_matching")
    data class DropMatching(val pattern: String) : CompressionRule

    /**
     * When line count exceeds [head] + [tail], keep the first [head] and last
     * [tail] lines. If [salience] is set, middle lines matching it (case-insensitive)
     * are also retained in place — up to [salienceCap] of them — so a decisive error
     * buried in the middle of a long log survives truncation; remaining elided runs
     * collapse to a single "… N lines elided …" marker. Without [salience] the whole
     * middle collapses to one marker, as before.
     */
    @Serializable
    @SerialName("head_tail")
    data class HeadTail(
        val head: Int,
        val tail: Int,
        val salience: String? = null,
        val salienceCap: Int = 30,
    ) : CompressionRule

    /**
     * Collapse runs of identical adjacent lines into a single line, appending an
     * occurrence count (e.g. `Error: timeout (×14)`) when the run is longer than
     * one. Order-preserving; never drops unique content — safe as a default.
     */
    @Serializable
    @SerialName("collapse_consecutive_duplicates")
    data object CollapseConsecutiveDuplicates : CompressionRule
}
