package ai.openclaw.android.node

import ai.openclaw.android.gateway.parseInvokeErrorFromThrowable
import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.JsonNull
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.JsonPrimitive

const val DEFAULT_SEAM_COLOR_ARGB: Long = 0xFF4F7A9A

data class Quad<A, B, C, D>(val first: A, val second: B, val third: C, val fourth: D)

fun String.toJsonString(): String {
  val escaped =
    this.replace("\\", "\\\\")
      .replace("\"", "\\\"")
      .replace("\n", "\\n")
      .replace("\r", "\\r")
  return "\"$escaped\""
}

fun JsonElement?.asObjectOrNull(): JsonObject? = this as? JsonObject

fun JsonElement?.asStringOrNull(): String? =
  when (this) {
    is JsonNull -> null
    is JsonPrimitive -> content
    else -> null
  }

fun parseHexColorArgb(raw: String?): Long? {
  val trimmed = raw?.trim().orEmpty()
  if (trimmed.isEmpty()) return null
  val hex = if (trimmed.startsWith("#")) trimmed.drop(1) else trimmed
  if (hex.length != 6) return null
  val rgb = hex.toLongOrNull(16) ?: return null
  return 0xFF000000L or rgb
}

fun invokeErrorFromThrowable(err: Throwable): Pair<String, String> {
  val parsed = parseInvokeErrorFromThrowable(err, fallbackMessage = "UNAVAILABLE: error")
  val message = if (parsed.hadExplicitCode) parsed.prefixedMessage else parsed.message
  return parsed.code to message
}

fun normalizeMainKey(raw: String?): String? {
  val trimmed = raw?.trim().orEmpty()
  return if (trimmed.isEmpty()) null else trimmed
}

fun isCanonicalMainSessionKey(key: String): Boolean {
  return key == "main"
}
