package com.correx.core.validation.artifact

import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.JsonPrimitive

/**
 * Why a producer's artifact output could not be resolved deterministically. Drives the policy
 * decision and gates whether the (expensive) LLM-repair rung is worth attempting.
 * See docs/specs/2026-07-04-artifact-emission-pipeline.md §3.2.
 */
enum class ArtifactFailure {
    FORMATTING,     // couldn't parse to a JSON object at all → deterministic repair (already tried)
    SCHEMA,         // parsed, wrong shape: unknown/extra property or type mismatch → LLM repair
    MISSING_INFO,   // parsed & shaped, but required content absent/empty → LLM repair
    CONTRADICTORY,  // internally inconsistent → regenerate producer
    UNSAFE,         // forbidden output (path traversal, secret) → reject immediately
}

/**
 * Pure classifier. `UNSAFE` is checked first (cheapest + terminal). Ordering matters: this runs
 * before the LLM-repair rung so that rung is only reached for `SCHEMA` / `MISSING_INFO`.
 *
 * ponytail: UNSAFE here is a lightweight `..` path-traversal heuristic. Full workspace-escape /
 * denied-tool / secret-scanning lives in the orchestrator's policy layer, which has the workspace
 * context this pure function does not. CONTRADICTORY needs semantic cross-field checks and is not
 * auto-detected yet — the enum value exists for the policy mapping.
 */
fun classify(raw: String, parsed: JsonObject?, schemaIssues: List<String>): ArtifactFailure = when {
    isUnsafe(parsed) -> ArtifactFailure.UNSAFE
    parsed == null -> ArtifactFailure.FORMATTING
    schemaIssues.any { it.startsWith("missing required") } -> ArtifactFailure.MISSING_INFO
    else -> ArtifactFailure.SCHEMA
}

private fun isUnsafe(parsed: JsonObject?): Boolean {
    val path = (parsed?.get("path") as? JsonPrimitive)?.takeIf { it.isString }?.content ?: return false
    return path.split('/', '\\').any { it == ".." }
}
