package com.correx.core.talkie

import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.JsonPrimitive
import kotlinx.serialization.json.contentOrNull
import kotlinx.serialization.json.jsonArray
import kotlinx.serialization.json.jsonObject
import kotlinx.serialization.json.jsonPrimitive

/**
 * Parses an optional `ideas` block out of a router chat reply: the rubber-duck path may end its prose
 * with a fenced ```` ```json {"ideas":["…","…"]} ``` ```` block to save ideas that crystallized.
 * Lenient and fence-tolerant — scans every fenced block for the one carrying an `ideas` array, accepts
 * string items or `{text|idea}` objects, and any parse failure or empty array yields no ideas. Returns
 * the reply with that block stripped (so the operator reads only prose), mirroring [WorkflowProposals].
 */
object Ideas {

    data class Parsed(val cleanText: String, val ideas: List<String>)

    private val json = Json { ignoreUnknownKeys = true; isLenient = true }
    private val fence = Regex("```(?:json)?\\s*(.*?)```", RegexOption.DOT_MATCHES_ALL)

    fun parse(content: String): Parsed = runCatching {
        fence.findAll(content).firstNotNullOfOrNull { match ->
            val obj = runCatching { json.parseToJsonElement(match.groupValues[1].trim()).jsonObject }.getOrNull()
            val array = obj?.get("ideas")?.jsonArray ?: return@firstNotNullOfOrNull null
            val ideas = array.mapNotNull { element ->
                when (element) {
                    is JsonObject -> (element["text"] ?: element["idea"])?.jsonPrimitive?.contentOrNull
                    is JsonPrimitive -> element.contentOrNull
                    else -> null
                }?.trim()?.ifBlank { null }
            }
            ideas.takeIf { it.isNotEmpty() }?.let { Parsed(content.removeRange(match.range).trim(), it) }
        } ?: Parsed(cleanText = content, ideas = emptyList())
    }.getOrElse { Parsed(cleanText = content, ideas = emptyList()) }
}
