package com.optix.android.tools.cloud

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.engine.EnvironmentManager
import com.optix.android.tools.engine.ShellExecutor
import com.optix.android.tools.registry.BaseTool
import javax.inject.Inject

/**
 * Kubernetes reconnaissance tool — enumerates clusters, namespaces, pods, and
 * surfaces common misconfigurations via read-only `kubectl` commands.
 *
 * Read-only by design: every command is a `get`/`describe`/`auth can-i` and no
 * resources are modified. Requires `kubectl` inside Termux and a reachable
 * kubeconfig/context.
 *
 * AUTHORIZED TESTING ONLY.
 */
class KubeReconTool @Inject constructor(
    private val shell: ShellExecutor,
) : BaseTool() {

    override val metadata = ToolMetadata(
        name = "kube_recon_termux",
        displayName = "Kubernetes Recon (Termux)",
        description = "Read-only Kubernetes reconnaissance: enumerate contexts, namespaces, pods, RBAC, and detect common misconfigurations (privileged pods, wildcard verbs, exposed dashboards). Requires kubectl.",
        category = ToolCategory.CONTAINER_SEC,
        parameters = listOf(
            ToolParam(
                name = "context",
                type = ParamType.STRING,
                description = "kubectl context to use (default: current-context)",
                required = false,
                defaultValue = "",
            ),
            ToolParam(
                name = "namespace",
                type = ParamType.STRING,
                description = "Namespace to scope the recon (default: all namespaces)",
                required = false,
                defaultValue = "",
            ),
            ToolParam(
                name = "deep",
                type = ParamType.BOOLEAN,
                description = "Include RBAC, secrets metadata, and service accounts",
                required = false,
                defaultValue = "false",
            ),
        ),
        requiresRoot = false,
        requiresNetwork = true,
        requiresTermux = true,
        requiredPackages = listOf("kubectl"),
        supportedPlatforms = listOf("Android", "Linux", "macOS"),
        chainSuggestions = listOf("docker_inspect_termux", "aws_inspector"),
    )

    override suspend fun execute(params: Map<String, Any>, emit: suspend (ToolEvent) -> Unit) {
        val context = param(params, "context") ?: ""
        val namespace = param(params, "namespace") ?: ""
        val deep = paramBool(params, "deep", false)

        emit(ToolEvent.Log("☸️ Kubernetes recon starting..."))
        if (context.isNotBlank()) emit(ToolEvent.Log("Context: $context"))
        if (namespace.isNotBlank()) emit(ToolEvent.Log("Namespace: $namespace"))
        emit(ToolEvent.Log(""))

        val termux = "${EnvironmentManager.TERMUX_BIN}/kubectl"
        val probe = shell.exec("$termux version --client --short", root = false)
        if (probe.stdout.contains("command not found", true) || probe.exitCode != 0 && probe.stdout.isBlank()) {
            emit(ToolEvent.TermuxMissing("kubectl", "kubectl"))
            emit(ToolEvent.Error("kubectl not found in Termux. Install it: pkg install kubectl"))
            emit(ToolEvent.Done)
            return
        }

        val ctxArg = if (context.isNotBlank()) listOf("--context", shell.sanitizeArg(context)) else emptyList()
        val nsArg = if (namespace.isNotBlank()) listOf("-n", shell.sanitizeArg(namespace)) else listOf("-A")

        runCatching {
            runKubectl(ctxArg + listOf("get", "nodes", "-o", "wide"), emit)
            runKubectl(ctxArg + nsArg + listOf("get", "pods", "-o", "wide"), emit)
            runKubectl(ctxArg + listOf("get", "ns"), emit)
            runKubectl(ctxArg + listOf("get", "svc") + nsArg, emit)

            // Privileged / host-namespace pods (misconfiguration signal)
            runKubectl(
                ctxArg + nsArg + listOf(
                    "get", "pods", "-o",
                    "jsonpath={range .items[?(@.spec.containers[?(@.securityContext.privileged)])]}" +
                        "{'PRIVILEGED: '}{.metadata.namespace}{'/'}{.metadata.name}{'\n'}{end}",
                ),
                emit,
                "Privileged pods",
            )

            if (deep) {
                runKubectl(ctxArg + nsArg + listOf("get", "sa"), emit)
                runKubectl(ctxArg + listOf("get", "clusterroles", "-o", "name"), emit)
                runKubectl(ctxArg + listOf("auth", "can-i", "--list"), emit)
                runKubectl(ctxArg + nsArg + listOf("get", "secrets"), emit)
            }

            emit(ToolEvent.Log(""))
            emit(ToolEvent.Log("✅ Kubernetes recon complete (read-only)."))
        }.onFailure {
            emit(ToolEvent.Error("Kubectl recon failed: ${it.message}"))
        }

        emit(ToolEvent.Done)
    }

    private suspend fun runKubectl(args: List<String>, emit: suspend (ToolEvent) -> Unit, label: String? = null) {
        if (label != null) emit(ToolEvent.Log("── $label ──"))
        val cmd = "${EnvironmentManager.TERMUX_BIN}/kubectl ${args.joinToString(" ")}"
        val result = shell.exec(cmd, root = false, timeoutMs = 30_000)
        result.stdout.lineSequence().filter { it.isNotBlank() }.forEach { emit(ToolEvent.Log(it)) }
        if (result.stderr.isNotBlank()) result.stderr.lineSequence().filter { it.isNotBlank() }.forEach {
            emit(ToolEvent.Log(it, com.optix.android.domain.model.LogLevel.WARN))
        }
    }
}
