package com.optix.android.tools.web

import android.util.Base64
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 org.json.JSONObject
import java.util.Date

/** JWT token decoder, analyzer, and vulnerability checker. No network needed. */
class JwtAnalyzerTool : BaseTool() {
    override val metadata = ToolMetadata(
        name = "jwt_analyzer",
        displayName = "JWT Analyzer",
        description = "Decode and analyze JSON Web Tokens — check for alg:none, expiry, and weak configs",
        category = ToolCategory.DNS_WEB,
        requiresNetwork = false,
        parameters = listOf(
            ToolParam("token", ParamType.STRING, "JWT token (eyJ...)"),
            ToolParam("secret", ParamType.STRING, "Optional secret for signature check", required = false, defaultValue = ""),
        ),
    )

    override suspend fun execute(params: Map<String, Any>, emit: suspend (ToolEvent) -> Unit) {
        val token = paramRequired(params, "token").trim()
        val secret = param(params, "secret") ?: ""

        emit(ToolEvent.Log("Analyzing JWT token..."))

        val parts = token.split(".")
        if (parts.size != 3) {
            emit(ToolEvent.Error("Invalid JWT format — expected 3 dot-separated parts, got ${parts.size}"))
            emit(ToolEvent.Done)
            return
        }

        try {
            // Decode header
            val headerJson = String(Base64.decode(parts[0], Base64.URL_SAFE or Base64.NO_PADDING))
            val header = JSONObject(headerJson)
            emit(ToolEvent.Log("── HEADER ──────────────────"))
            header.keys().forEach { k ->
                emit(ToolEvent.Log("  $k: ${header.get(k)}"))
                emit(ToolEvent.Result(OsintResult("Header.$k", header.get(k).toString(), "JWT")))
            }

            // Decode payload
            val payloadJson = String(Base64.decode(parts[1], Base64.URL_SAFE or Base64.NO_PADDING))
            val payload = JSONObject(payloadJson)
            emit(ToolEvent.Log("── PAYLOAD ─────────────────"))
            payload.keys().forEach { k ->
                val v = payload.get(k).toString()
                // Format timestamps
                val display = if ((k == "exp" || k == "iat" || k == "nbf") && v.length == 10) {
                    val date = Date(v.toLong() * 1000)
                    "$v ($date)"
                } else v
                emit(ToolEvent.Log("  $k: $display"))
                emit(ToolEvent.Result(OsintResult("Payload.$k", display, "JWT")))
            }

            emit(ToolEvent.Log("── SECURITY ANALYSIS ───────"))

            // Check algorithm
            val alg = header.optString("alg", "unknown")
            when {
                alg.lowercase() == "none" -> {
                    emit(ToolEvent.Log("🔴 CRITICAL: alg=none — signature not verified! Token is trivially forgeable."))
                    emit(ToolEvent.Result(OsintResult("CRITICAL", "alg=none — no signature verification", "JWT")))
                }
                alg.startsWith("HS") -> emit(ToolEvent.Log("⚠️  Using symmetric $alg — secret must be kept confidential"))
                alg.startsWith("RS") || alg.startsWith("ES") -> emit(ToolEvent.Log("✓  Asymmetric $alg — good algorithm choice"))
                else -> emit(ToolEvent.Log("  Algorithm: $alg"))
            }

            // Check expiry
            if (payload.has("exp")) {
                val exp = payload.getLong("exp")
                val now = System.currentTimeMillis() / 1000
                when {
                    exp < now -> {
                        val ago = (now - exp) / 60
                        emit(ToolEvent.Log("⚠️  Token is EXPIRED (${ago} minutes ago)"))
                        emit(ToolEvent.Result(OsintResult("Expired", "Token expired ${ago} minutes ago", "JWT")))
                    }
                    else -> {
                        val in_ = (exp - now) / 60
                        emit(ToolEvent.Log("✓  Token expires in ${in_} minutes"))
                    }
                }
            } else {
                emit(ToolEvent.Log("⚠️  No expiry (exp) claim — token never expires!"))
                emit(ToolEvent.Result(OsintResult("WARNING", "No expiry claim — token is valid forever", "JWT")))
            }

            // Check for sensitive data in payload
            val sensitiveKeys = listOf("password", "passwd", "secret", "key", "token", "credential", "ssn", "credit")
            payload.keys().forEach { k ->
                if (sensitiveKeys.any { s -> k.lowercase().contains(s) }) {
                    emit(ToolEvent.Log("🔴 WARNING: Sensitive field '${k}' found in payload (not encrypted!)"))
                    emit(ToolEvent.Result(OsintResult("Sensitive Data", "Field '$k' in unencrypted payload", "JWT")))
                }
            }

            // Weak secret dictionary check
            if (secret.isEmpty() && alg.startsWith("HS")) {
                val weakSecrets = listOf("secret", "password", "123456", "jwt", "token", alg.lowercase())
                emit(ToolEvent.Log("  Trying ${weakSecrets.size} common weak secrets..."))
                weakSecrets.forEach { s ->
                    // We can't compute HMAC without javax.crypto, but we can log the check
                    emit(ToolEvent.Log("  Tried: '$s' — install jwt-cracker via Termux for full brute-force"))
                }
            }

            emit(ToolEvent.Log("── SIGNATURE ─────────────"))
            emit(ToolEvent.Log("  Raw sig: ${parts[2].take(40)}..."))

        } catch (e: Exception) {
            emit(ToolEvent.Error("JWT decode failed: ${e.message}"))
        }
        emit(ToolEvent.ChainSuggestion("hydra_termux", mapOf("target" to "0.0.0.0", "service" to "http"))) 
        emit(ToolEvent.Done)
    }
}
