package com.optix.android.ai

import com.optix.android.tools.registry.ToolRegistry
import com.optix.android.util.NetworkUtils
import timber.log.Timber
import javax.inject.Inject
import javax.inject.Singleton

/**
 * Tool dispatch engine that maps parsed intents to actual tool calls.
 * 
 * Responsible for:
 * - Extracting parameters from regex matches
 * - Validating tool names against the registry
 * - Building tool call structures with proper parameter maps
 * - Managing contextual follow-up logic after tool execution
 * 
 * @property networkUtils Provides network context (subnet info, etc.)
 * @property toolRegistry Registry of all available tools
 * @property intentParser Parser for extracting parameters from matches
 */
@Singleton
class ToolDispatcher @Inject constructor(
    private val networkUtils: NetworkUtils,
    private val toolRegistry: ToolRegistry,
    private val intentParser: IntentParser,
) {

    /** Last executed tool name for contextual follow-ups */
    private var lastToolName: String? = null
    
    /** Last tool result for contextual analysis */
    private var lastToolResult: String? = null

    /**
     * Records the result of a tool execution for contextual follow-ups.
     */
    fun recordToolResult(toolName: String, result: String) {
        lastToolName = toolName
        lastToolResult = result
    }

    /**
     * Clears the last tool context.
     */
    fun clearContext() {
        lastToolName = null
        lastToolResult = null
    }

    /**
     * Validates that all tool names in DISPATCH_TOOL_NAMES exist in the registry.
     * Logs warnings for any mismatches at startup.
     */
    fun validateToolNames() {
        val registeredNames = toolRegistry.listNames().toSet()
        DISPATCH_TOOL_NAMES.forEach { name ->
            if (name !in registeredNames) {
                Timber.w("ToolDispatcher: tool '$name' not found in ToolRegistry")
            }
        }
    }

    /**
     * Dispatches a tool call based on the pattern index.
     * 
     * @param patternIndex Index into the tool dispatch patterns
     * @param match Regex match result containing extracted parameters
     * @return Pair of tool name and parameter map
     */
    fun dispatchToolCall(patternIndex: Int, match: MatchResult): Pair<String, Map<String, Any>> {
        val subnet = localSubnet()
        
        return when (patternIndex) {
            // Network Scanning
            0 -> "network_scanner" to mapOf("target" to match.gv(1))
            1 -> "port_scanner" to mapOf("target" to match.gv(1))
            2 -> "port_scanner" to mapOf("target" to match.gv(1))
            3 -> {
                val s = match.gv(1).ifEmpty { subnet }
                "lan_scanner" to mapOf("subnet" to s)
            }
            4 -> "netbios_scanner" to mapOf("target" to match.gv(1))
            5 -> "wifi_scanner" to emptyMap()
            6 -> "traceroute" to mapOf("target" to match.gv(1))
            7 -> "nmap_termux" to mapOf("target" to match.gv(1))
            8 -> "arp_scan" to emptyMap()
            9 -> "ssh_audit" to mapOf("target" to match.gv(1))
            10 -> "masscan_termux" to mapOf("target" to match.gv(1))
            11 -> "rping3_termux" to mapOf("target" to match.gv(1))
            12 -> "packet_sniffer" to emptyMap()
            13 -> "network_topology" to emptyMap()
            14 -> "legion_termux" to mapOf("target" to match.gv(1))

            // DNS & Web
            15 -> "dns_recon" to mapOf("domain" to match.gv(1))
            16 -> "subdomain_enum" to mapOf("domain" to match.gv(1))
            17 -> "http_inspector" to mapOf("url" to match.gv(1))
            18 -> "directory_fuzzer" to mapOf("url" to match.gv(1))
            19 -> "sqli_tester" to mapOf("url" to match.gv(1))
            20 -> "xss_scanner" to mapOf("url" to match.gv(1))
            21 -> "cors_checker" to mapOf("url" to match.gv(1))
            22 -> "security_headers" to mapOf("url" to match.gv(1))
            23 -> "jwt_analyzer" to mapOf("token" to match.gv(1))
            24 -> "nikto_termux" to mapOf("target" to match.gv(1))
            25 -> "sqlmap_termux" to mapOf("url" to match.gv(1))

            // OSINT
            26 -> "shodan_search" to mapOf("query" to match.gv(1))
            27 -> "shodan_host" to mapOf("ip" to match.gv(1))
            28 -> "theharvester" to mapOf("domain" to match.gv(1))
            29 -> "hibp_check" to mapOf("email" to match.gv(1))
            30 -> "hunter_verify" to mapOf("domain" to match.gv(1))

            // Exploit / Attack
            31 -> "brute_force" to mapOf("protocol" to match.gv(1), "target" to match.gv(2))
            32 -> "hydra_termux" to mapOf("target" to match.gv(1), "service" to match.gv(2))
            33 -> "payload_generator" to mapOf("type" to match.gv(1), "lhost" to match.gv(2), "lport" to match.gv(3))
            34 -> "reverse_shell_gen" to mapOf("language" to match.gv(1), "host" to match.gv(2), "port" to match.gv(3))

            // LPE & Lateral Movement
            35 -> "linpeas" to emptyMap()
            36 -> "winpeas" to mapOf("target" to match.gv(1))
            37 -> "bloodhound" to emptyMap()
            38 -> {
                val t = match.gv(2)
                if (t.isNotEmpty()) {
                    "cme" to mapOf("target" to t)
                } else {
                    "cme" to emptyMap()
                }
            }

            // Cloud Security
            39 -> "aws_inspector" to emptyMap()
            40 -> "gcp_asset_tool" to emptyMap()
            41 -> "azure_ad_tool" to emptyMap()

            // Utility
            42 -> "hash_cracker" to mapOf("hash" to match.gv(1))
            43 -> "password_generator" to emptyMap()
            44 -> "encoder_tool" to mapOf("mode" to match.gv(1), "input" to match.gv(2))
            45 -> "encoder_tool" to mapOf("mode" to match.gv(1), "input" to match.gv(2))
            46 -> "subnet_calculator" to mapOf("cidr" to match.gv(1))
            47 -> "hash_generator" to mapOf("input" to match.gv(1))
            48 -> "cipher_tool" to mapOf("mode" to match.gv(1), "text" to match.gv(2))
            49 -> "cipher_tool" to mapOf("mode" to "rot13", "text" to match.gv(1))
            50 -> "regex_tester" to mapOf("pattern" to match.gv(1), "text" to match.gv(2))

            else -> throw IllegalArgumentException("Invalid tool pattern index: $patternIndex")
        }
    }

    /**
     * Dispatches a natural language tool pattern.
     * 
     * @param patternIndex Index into the NL tool patterns
     * @param match Regex match result
     * @return Pair of tool name and parameter map
     */
    fun dispatchNaturalLanguageTool(patternIndex: Int, match: MatchResult): Pair<String, Map<String, Any>> {
        val subnet = localSubnet()
        
        return when (patternIndex) {
            0 -> "lan_scanner" to mapOf("subnet" to subnet)
            1 -> "port_scanner" to mapOf("target" to match.gv(4), "start_port" to "1", "end_port" to "9999")
            2 -> "port_scanner" to mapOf("target" to match.gv(5), "start_port" to "1", "end_port" to "9999")
            3 -> "traceroute" to mapOf("target" to match.gv(3))
            4 -> "wifi_scanner" to emptyMap()
            5 -> "password_generator" to emptyMap()
            6 -> "password_generator" to emptyMap() // Hash generation prompt (no tool call)
            else -> throw IllegalArgumentException("Invalid NL pattern index: $patternIndex")
        }
    }

    /**
     * Generates contextual follow-up tool calls based on the last executed tool.
     * 
     * @param lower Lowercase user input
     * @return Pair of tool name and parameters, or null if no follow-up applicable
     */
    fun generateContextualFollowUp(lower: String): Pair<String, Map<String, Any>>? {
        val subnet = localSubnet()
        
        return when (lastToolName) {
            "lan_scanner" -> {
                val target = Regex("""([\d.]+)""").find(lower)?.value
                if (target != null) {
                    "port_scanner" to mapOf("target" to target, "start_port" to "1", "end_port" to "9999")
                } else {
                    null
                }
            }
            "port_scanner", "nmap_termux" -> {
                val result = lastToolResult ?: ""
                val openPorts = extractOpenPorts(result)
                suggestVulnTool(openPorts, lower, result)
            }
            "ssh_audit" -> {
                val target = Regex("""([\d.]+)""").find(lower)?.value ?: return null
                "hydra_termux" to mapOf("target" to target, "service" to "ssh")
            }
            "http_inspector", "security_headers" -> null // Handled by response templates
            "wifi_scanner" -> "lan_scanner" to mapOf("subnet" to subnet)
            else -> null
        }
    }

    /**
     * Analyzes open ports and suggests appropriate vulnerability testing tools.
     * 
     * @param openPorts List of open port numbers
     * @param lower Lowercase user input
     * @param result Last tool result for OS detection
     * @return Suggested tool call or null
     */
    fun suggestVulnTool(openPorts: List<Int>, lower: String, result: String): Pair<String, Map<String, Any>>? {
        val target = Regex("""([\d.]+)""").find(lower)?.value ?: lastToolResult?.let {
            Regex("""Scanning ([\d.]+)""").find(it)?.groupValues?.get(1)
        } ?: return null

        // Prioritize web vulnerabilities
        if (openPorts.any { it in listOf(80, 443, 8080, 8443) }) {
            return "http_inspector" to mapOf("url" to "http://$target")
        }

        // SSH audit
        if (openPorts.any { it == 22 }) {
            return "ssh_audit" to mapOf("target" to target)
        }

        // SMB enumeration
        if (openPorts.any { it in listOf(445, 139) }) {
            return "netbios_scanner" to mapOf("target" to target)
        }

        // Database detection
        if (openPorts.any { it in listOf(3306, 5432, 27017, 6379) }) {
            return "nmap_termux" to mapOf("target" to target)
        }

        // Default to nmap for detailed service detection
        return "nmap_termux" to mapOf("target" to target)
    }

    // ──────────────────────────────────────────────────────────────────
    // Helper Functions
    // ──────────────────────────────────────────────────────────────────

    private fun localSubnet(): String =
        networkUtils.getLocalNetworkState().subnet ?: "192.168.1"

    private fun extractOpenPorts(result: String): List<Int> {
        return Regex("""(\d+)/tcp\s+open""").findAll(result)
            .map { it.groupValues[1].toInt() }
            .toList()
            .ifEmpty {
                Regex("""port (\d+)""").findAll(result)
                    .map { it.groupValues[1].toInt() }
                    .toList()
            }
    }

    private fun MatchResult.gv(n: Int): String = intentParser.run { gv(n) }

    companion object {
        /** All tool names referenced in dispatch — validated against ToolRegistry at startup */
        val DISPATCH_TOOL_NAMES = setOf(
            "network_scanner", "port_scanner", "lan_scanner", "netbios_scanner", "wifi_scanner",
            "traceroute", "nmap_termux", "arp_scan", "ssh_audit", "masscan_termux",
            "rping3_termux", "packet_sniffer", "network_topology", "legion_termux",
            "dns_recon", "subdomain_enum", "http_inspector", "directory_fuzzer", "sqli_tester",
            "xss_scanner", "cors_checker", "security_headers", "jwt_analyzer",
            "nikto_termux", "sqlmap_termux",
            "brute_force", "hydra_termux", "payload_generator", "reverse_shell_gen",
            "hash_cracker", "password_generator", "encoder_tool", "subnet_calculator",
            "hash_generator", "cipher_tool", "regex_tester",
            "shodan_search", "shodan_host", "theharvester", "hibp_check", "hunter_verify",
            "linpeas", "winpeas", "bloodhound", "cme",
        )
    }
}
