package com.optix.android.tools.web

import com.optix.android.domain.model.DirectoryResult
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.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.coroutineScope
import okhttp3.OkHttpClient
import okhttp3.Request

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

    override val metadata = ToolMetadata(
        name = "directory_fuzzer",
        displayName = "Directory Fuzzer",
        description = "Brute-force web directories and files on a target URL",
        category = ToolCategory.DNS_WEB,
        parameters = listOf(
            ToolParam("url", ParamType.STRING, "Target base URL"),
            ToolParam("wordlist", ParamType.STRING, "Comma-separated paths to probe", required = false, defaultValue = "admin,login,api,backup,config,.env,robots.txt,sitemap.xml"),
            ToolParam("status_filter", ParamType.STRING, "Comma-separated status codes to report", required = false, defaultValue = "200,201,301,302,403"),
        ),
    )

    override suspend fun execute(params: Map<String, Any>, emit: suspend (ToolEvent) -> Unit) {
        val baseUrl = paramRequired(params, "url").trimEnd('/')
        val wordlist = (param(params, "wordlist") ?: "admin,login,api").split(",").map { it.trim() }
        val statusFilter = (param(params, "status_filter") ?: "200,301,403").split(",").mapNotNull { it.trim().toIntOrNull() }.toSet()

        emit(ToolEvent.Log("Fuzzing $baseUrl (${wordlist.size} paths)"))

        coroutineScope {
            wordlist.mapIndexed { idx, path ->
                async(Dispatchers.IO) {
                    val url = "$baseUrl/$path"
                    runCatching {
                        val request = Request.Builder().url(url).head().build()
                        client.newCall(request).execute().use { response ->
                            if (response.code in statusFilter) {
                                val size = response.header("Content-Length")?.toLongOrNull() ?: 0L
                                emit(ToolEvent.Result(DirectoryResult(url, response.code, size)))
                                emit(ToolEvent.Log("  [${response.code}]  $url  (${size}B)"))
                            }
                        }
                    }
                    emit(ToolEvent.Progress(idx + 1, wordlist.size))
                }
            }.awaitAll()
        }

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