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

/** Tests for Cross-Origin Resource Sharing (CORS) misconfigurations. */
class CORSCheckerTool(private val client: OkHttpClient) : BaseTool() {
    override val metadata = ToolMetadata(
        name = "cors_checker",
        displayName = "CORS Checker",
        description = "Test for CORS misconfigurations that could allow cross-origin credential theft",
        category = ToolCategory.DNS_WEB,
        requiresNetwork = true,
        parameters = listOf(
            ToolParam("url", ParamType.STRING, "Target URL (e.g. https://example.com/api)"),
            ToolParam("origin", ParamType.STRING, "Test origin to inject", required = false, defaultValue = "https://evil.com"),
        ),
    )

    override suspend fun execute(params: Map<String, Any>, emit: suspend (ToolEvent) -> Unit) {
        val url = paramRequired(params, "url")
        val testOrigin = param(params, "origin") ?: "https://evil.com"

        emit(ToolEvent.Log("Testing CORS on $url with Origin: $testOrigin"))

        withContext(Dispatchers.IO) {
            val testOrigins = listOf(
                testOrigin,
                "null",
                "https://attacker.${url.substringAfter("://").substringBefore("/")}",
                "https://evil.com",
            ).distinct()

            testOrigins.forEach { origin ->
                try {
                    val req = Request.Builder()
                        .url(url)
                        .header("Origin", origin)
                        .header("User-Agent", "Mozilla/5.0 Optix/3.0")
                        .build()

                    val resp = client.newCall(req).execute()
                    val acao = resp.header("Access-Control-Allow-Origin")
                    val acac = resp.header("Access-Control-Allow-Credentials")
                    resp.close()

                    emit(ToolEvent.Log("Origin: $origin"))

                    when {
                        acao == null -> emit(ToolEvent.Log("  ✓ No ACAO header — CORS not enabled for this origin"))
                        acao == "*" && acac == "true" -> {
                            emit(ToolEvent.Log("  🔴 CRITICAL: Wildcard ACAO with credentials=true — this should be impossible but is extremely dangerous"))
                            emit(ToolEvent.Result(OsintResult("CRITICAL", "ACAO * with credentials=true — credential theft possible", "CORS")))
                        }
                        acao == "*" -> emit(ToolEvent.Log("  ⚠️  Wildcard ACAO (*) — public API, no credentials possible"))
                        acao == origin -> {
                            if (acac == "true") {
                                emit(ToolEvent.Log("  🔴 VULNERABLE: Origin reflected with credentials=true — cross-origin credential theft possible"))
                                emit(ToolEvent.Result(OsintResult("VULNERABLE", "Reflected Origin + credentials=true ($origin)", "CORS")))
                            } else {
                                emit(ToolEvent.Log("  ⚠️  Origin reflected in ACAO without credentials — cross-origin reads possible"))
                                emit(ToolEvent.Result(OsintResult("WARNING", "Origin reflected without credentials ($origin)", "CORS")))
                            }
                        }
                        acao == "null" -> {
                            emit(ToolEvent.Log("  🔴 VULNERABLE: null origin accepted — sandboxed iframes can exploit this"))
                            emit(ToolEvent.Result(OsintResult("VULNERABLE", "null origin accepted — sandbox exploit possible", "CORS")))
                        }
                        else -> emit(ToolEvent.Log("  ✓ ACAO=$acao — origin restricted correctly"))
                    }
                } catch (e: Exception) {
                    emit(ToolEvent.Log("  Error testing origin $origin: ${e.message}"))
                }
            }
        }
        emit(ToolEvent.ChainSuggestion("sqli_tester", mapOf("url" to url)))
        emit(ToolEvent.Done)
    }
}
