package com.optix.android.tools.utility

import com.optix.android.domain.model.OsintResult
import com.optix.android.domain.model.ParamType
import com.optix.android.domain.model.ToolCategory
import com.optix.android.domain.model.ToolEvent
import com.optix.android.domain.model.ToolMetadata
import com.optix.android.domain.model.ToolParam
import com.optix.android.tools.registry.BaseTool
import java.net.URLDecoder
import java.net.URLEncoder
import java.security.MessageDigest
import java.util.Base64

class EncoderTool : BaseTool() {

    override val metadata = ToolMetadata(
        name = "encoder_tool",
        displayName = "Encoder / Decoder",
        description = "Encode and decode data in Base64, URL, hex, and hash formats",
        category = ToolCategory.PAYLOADS_UTILITIES,
        requiresNetwork = false,
        parameters = listOf(
            ToolParam("operation", ParamType.ENUM, "Operation", defaultValue = "encode",
                enumValues = listOf("encode", "decode", "hash")),
            ToolParam("format", ParamType.ENUM, "Format", defaultValue = "base64",
                enumValues = listOf("base64", "url", "hex", "md5", "sha1", "sha256", "sha512")),
            ToolParam("input", ParamType.STRING, "Input data"),
        ),
    )

    override suspend fun execute(params: Map<String, Any>, emit: suspend (ToolEvent) -> Unit) {
        val operation = param(params, "operation") ?: "encode"
        val format = param(params, "format") ?: "base64"
        val input = paramRequired(params, "input")

        emit(ToolEvent.Log("$operation ($format): ${input.take(50)}"))

        val result = when (format) {
            "base64" -> when (operation) {
                "encode" -> Base64.getEncoder().encodeToString(input.toByteArray())
                "decode" -> runCatching { String(Base64.getDecoder().decode(input)) }.getOrElse { "Invalid Base64" }
                else -> "Unknown operation"
            }
            "url" -> when (operation) {
                "encode" -> URLEncoder.encode(input, "UTF-8")
                "decode" -> URLDecoder.decode(input, "UTF-8")
                else -> "Unknown operation"
            }
            "hex" -> when (operation) {
                "encode" -> input.toByteArray().joinToString("") { "%02x".format(it) }
                "decode" -> runCatching {
                    input.chunked(2).map { it.toInt(16).toByte() }.toByteArray().let { String(it) }
                }.getOrElse { "Invalid hex" }
                else -> "Unknown operation"
            }
            "md5", "sha1", "sha256", "sha512" -> {
                val algo = format.uppercase().replace("SHA", "SHA-")
                MessageDigest.getInstance(algo).digest(input.toByteArray()).joinToString("") { "%02x".format(it) }
            }
            else -> "Unknown format"
        }

        emit(ToolEvent.Result(OsintResult("$operation/$format", result, "EncoderTool")))
        emit(ToolEvent.Log("  Result: $result"))
        emit(ToolEvent.ChainSuggestion("hash_cracker", mapOf("hash" to result)))
        emit(ToolEvent.Done)
    }
}
