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
import org.json.JSONArray
import org.json.JSONException
import java.util.regex.Pattern

class NativeWpScanTool(private val client: OkHttpClient) : BaseTool() {
    override val metadata = ToolMetadata(
        name = "native_wpscan",
        displayName = "WPScan (Native)",
        description = "Native WordPress vulnerability scanner — finds plugins, themes, users. (Offline/Heuristic mode, no CVE API).",
        category = ToolCategory.DNS_WEB,
        requiresTermux = false,
        requiresRoot = false,
        parameters = listOf(
            ToolParam("url", ParamType.STRING, "WordPress site URL (e.g. https://example.com)"),
        ),
        chainSuggestions = listOf("native_whatweb", "directory_fuzzer"),
    )

    override suspend fun execute(params: Map<String, Any>, emit: suspend (ToolEvent) -> Unit) {
        var url = paramRequired(params, "url").trimEnd('/')
        if (!url.startsWith("http://") && !url.startsWith("https://")) {
            url = "http://$url"
        }

        emit(ToolEvent.Log("[WPScan] Scanning WordPress at $url natively (Heuristic Mode)..."))
        emit(ToolEvent.Log("Note: CVE API lookups are excluded for native offline scanning speed."))

        withContext(Dispatchers.IO) {
            try {
                // 1. Fetch Main Page for Version & Plugins
                val request = Request.Builder().url(url).build()
                client.newCall(request).execute().use { response ->
                    val body = response.body?.string() ?: ""
                    
                    // Version Check
                    val versionMatcher = Pattern.compile("<meta name=\"generator\" content=\"WordPress (.*?)\"", Pattern.CASE_INSENSITIVE).matcher(body)
                    if (versionMatcher.find()) {
                        val version = versionMatcher.group(1)?.trim() ?: "Unknown"
                        emit(ToolEvent.Result(OsintResult("WP Version", version, url)))
                        emit(ToolEvent.Log("[WPScan] WordPress Version Detected: $version"))
                    } else {
                         emit(ToolEvent.Log("[WPScan] Could not reliably detect WordPress version from generator tag."))
                    }

                    // Plugin Discovery (regex for wp-content/plugins/xyz/)
                    val pluginMatcher = Pattern.compile("wp-content/plugins/([^/\"']+)", Pattern.CASE_INSENSITIVE).matcher(body)
                    val plugins = mutableSetOf<String>()
                    while (pluginMatcher.find()) {
                        pluginMatcher.group(1)?.let { plugins.add(it) }
                    }
                    if (plugins.isNotEmpty()) {
                        emit(ToolEvent.Log("[WPScan] Discovered Plugins: ${plugins.size}"))
                        plugins.forEach { plugin ->
                            emit(ToolEvent.Result(OsintResult("WP Plugin", plugin, url)))
                            emit(ToolEvent.Log("  - $plugin"))
                        }
                    }

                    // Theme Discovery
                    val themeMatcher = Pattern.compile("wp-content/themes/([^/\"']+)", Pattern.CASE_INSENSITIVE).matcher(body)
                    if (themeMatcher.find()) {
                        val theme = themeMatcher.group(1) ?: "Unknown"
                        emit(ToolEvent.Result(OsintResult("WP Theme", theme, url)))
                        emit(ToolEvent.Log("[WPScan] Active Theme: $theme"))
                    }
                }

                // 2. User Enumeration via REST API
                emit(ToolEvent.Log("[WPScan] Enumerating users via REST API..."))
                val restUrl = "$url/wp-json/wp/v2/users"
                val restReq = Request.Builder().url(restUrl).build()
                client.newCall(restReq).execute().use { restResp ->
                    if (restResp.isSuccessful) {
                        val json = restResp.body?.string() ?: ""
                        try {
                            val usersArray = JSONArray(json)
                            if (usersArray.length() > 0) {
                                emit(ToolEvent.Log("[WPScan] Found ${usersArray.length()} users:"))
                                for (i in 0 until usersArray.length()) {
                                    val userObj = usersArray.getJSONObject(i)
                                    val id = userObj.optInt("id", -1)
                                    val name = userObj.optString("name", "Unknown")
                                    val slug = userObj.optString("slug", "Unknown")
                                    emit(ToolEvent.Result(OsintResult("WP User", "$slug (ID: $id, Name: $name)", restUrl)))
                                    emit(ToolEvent.Log("  - ID: $id | Slug: $slug | Name: $name"))
                                }
                            } else {
                                emit(ToolEvent.Log("[WPScan] REST API exposed but no users found."))
                            }
                        } catch (e: JSONException) {
                            emit(ToolEvent.Log("[WPScan] Failed to parse REST API JSON response."))
                        }
                    } else {
                         emit(ToolEvent.Log("[WPScan] REST API enumeration failed. Endpoint may be disabled (HTTP ${restResp.code})."))
                    }
                }
            } catch (e: Exception) {
                emit(ToolEvent.Error("WPScan failed: ${e.message}", e))
            }
        }
        emit(ToolEvent.ChainSuggestion("directory_fuzzer", mapOf("url" to url)))
        emit(ToolEvent.Done)
    }
}
