package com.optix.android.tools.web

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 kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import okhttp3.OkHttpClient
import okhttp3.Request

/** Comprehensive HTTP security header audit. */
class SecurityHeadersTool(private val client: OkHttpClient) : BaseTool() {
    override val metadata = ToolMetadata(
        name = "security_headers",
        displayName = "Security Headers",
        description = "Full HTTP security header audit: CSP, HSTS, X-Frame-Options, and more",
        category = ToolCategory.DNS_WEB,
        requiresNetwork = true,
        parameters = listOf(
            ToolParam("url", ParamType.STRING, "Target URL (include https://)"),
            ToolParam("follow_redirects", ParamType.BOOLEAN, "Follow redirects", required = false, defaultValue = "true"),
        ),
    )

    data class HeaderCheck(
        val name: String,
        val critical: Boolean,
        val description: String,
        val goodPattern: Regex? = null,
    )

    private val checks = listOf(
        HeaderCheck("Strict-Transport-Security", true,
            "Forces HTTPS. Missing = HTTPS downgrade attacks possible.",
            Regex("max-age=\\d+")),
        HeaderCheck("Content-Security-Policy", true,
            "Prevents XSS by whitelisting trusted content sources."),
        HeaderCheck("X-Frame-Options", true,
            "Prevents clickjacking attacks. Should be SAMEORIGIN or DENY."),
        HeaderCheck("X-Content-Type-Options", false,
            "Prevents MIME sniffing. Should be 'nosniff'.",
            Regex("nosniff", RegexOption.IGNORE_CASE)),
        HeaderCheck("Referrer-Policy", false,
            "Controls how much referrer info is sent. Should restrict cross-origin leakage."),
        HeaderCheck("Permissions-Policy", false,
            "Restricts browser features (camera, microphone, geolocation)."),
        HeaderCheck("X-XSS-Protection", false,
            "Legacy XSS filter (mostly deprecated, CSP is preferred)."),
        HeaderCheck("Cross-Origin-Opener-Policy", false,
            "Prevents cross-origin window attacks. Should be same-origin."),
        HeaderCheck("Cross-Origin-Resource-Policy", false,
            "Prevents cross-origin reads of sensitive resources."),
        HeaderCheck("Cross-Origin-Embedder-Policy", false,
            "Required for SharedArrayBuffer. Should be require-corp."),
    )

    override suspend fun execute(params: Map<String, Any>, emit: suspend (ToolEvent) -> Unit) {
        val url = paramRequired(params, "url")
        emit(ToolEvent.Log("Auditing security headers for $url..."))

        withContext(Dispatchers.IO) {
            try {
                val req = Request.Builder()
                    .url(url)
                    .header("User-Agent", "Mozilla/5.0 Optix/3.0 SecurityAudit")
                    .build()

                val resp = client.newCall(req).execute()
                val code = resp.code
                emit(ToolEvent.Log("Response: HTTP $code"))
                emit(ToolEvent.Log("Server: ${resp.header("Server") ?: "unknown"}"))
                emit(ToolEvent.Log(""))

                var passed = 0
                var failed = 0

                checks.forEach { check ->
                    val value = resp.header(check.name)
                    when {
                        value == null -> {
                            val severity = if (check.critical) "🔴 MISSING" else "🟡 MISSING"
                            emit(ToolEvent.Log("$severity  ${check.name}"))
                            emit(ToolEvent.Log("         ${check.description}"))
                            emit(ToolEvent.Result(OsintResult(
                                if (check.critical) "Critical" else "Warning",
                                "Missing: ${check.name} — ${check.description}",
                                "SecurityHeaders"
                            )))
                            failed++
                        }
                        check.goodPattern != null && !check.goodPattern.containsMatchIn(value) -> {
                            emit(ToolEvent.Log("⚠️  WEAK     ${check.name}: $value"))
                            emit(ToolEvent.Result(OsintResult("Weak", "${check.name}: $value", "SecurityHeaders")))
                            failed++
                        }
                        else -> {
                            emit(ToolEvent.Log("✓  PRESENT  ${check.name}: ${value.take(60)}"))
                            passed++
                        }
                    }
                }

                resp.close()
                emit(ToolEvent.Log(""))
                emit(ToolEvent.Log("Score: $passed/${checks.size} headers present (${(passed * 100) / checks.size}%)"))
                val grade = when {
                    passed >= 9 -> "A+"
                    passed >= 7 -> "A"
                    passed >= 5 -> "B"
                    passed >= 3 -> "C"
                    else        -> "F"
                }
                emit(ToolEvent.Log("Grade: $grade"))
                emit(ToolEvent.Result(OsintResult("Grade", "$grade — $passed/${checks.size} headers pass", "SecurityHeaders")))
            } catch (e: Exception) {
                emit(ToolEvent.Error("Security headers check failed: ${e.message}"))
            }
        }
        emit(ToolEvent.ChainSuggestion("http_inspector", mapOf("url" to url)))
        emit(ToolEvent.Done)
    }
}
