package com.optix.android.tools.network

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 jcifs.CIFSContext
import jcifs.context.BaseContext
import jcifs.smb.NtlmPasswordAuthenticator
import jcifs.smb.SmbFile
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.util.Properties

class NativeSmbScannerTool : BaseTool() {
    override val metadata = ToolMetadata(
        name = "native_smb_scanner",
        displayName = "SMB Scanner (Native)",
        description = "Native SMB enumeration and share discovery without Termux.",
        category = ToolCategory.NETWORK_SCANNING,
        requiresTermux = false,
        requiresRoot = false,
        parameters = listOf(
            ToolParam("target", ParamType.STRING, "Target IP or hostname"),
            ToolParam("username", ParamType.STRING, "Username (leave blank for null session)", required = false, defaultValue = ""),
            ToolParam("password", ParamType.STRING, "Password (leave blank for null session)", required = false, defaultValue = ""),
            ToolParam("domain", ParamType.STRING, "Domain", required = false, defaultValue = "")
        ),
        chainSuggestions = listOf("port_scanner", "nmap_termux"),
    )

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

        val authType = if (username.isEmpty() && password.isEmpty()) "Anonymous/Null Session" else "Authenticated"
        emit(ToolEvent.Log("[SMB] Connecting to smb://$target/ using $authType..."))

        withContext(Dispatchers.IO) {
            try {
                // Setup jcifs-ng properties
                val prop = Properties()
                prop.setProperty("jcifs.smb.client.enableSMB2", "true")
                prop.setProperty("jcifs.smb.client.disableSMB1", "false")
                prop.setProperty("jcifs.resolveOrder", "DNS")

                val baseContext: CIFSContext = BaseContext(jcifs.config.PropertyConfiguration(prop))
                
                val authContext = if (username.isEmpty() && password.isEmpty()) {
                    baseContext.withGuestCrendentials()
                } else {
                    baseContext.withCredentials(NtlmPasswordAuthenticator(domain, username, password))
                }

                val smbUrl = "smb://$target/"
                val smbFile = SmbFile(smbUrl, authContext)

                emit(ToolEvent.Log("[SMB] Successfully connected. Enumerating shares..."))
                
                val shares = smbFile.listFiles()
                if (shares == null || shares.isEmpty()) {
                    emit(ToolEvent.Log("[SMB] No shares found or access denied to list shares."))
                } else {
                    emit(ToolEvent.Log("[SMB] Found ${shares.size} shares:"))
                    for (share in shares) {
                        val shareName = share.name
                        val isHidden = shareName.endsWith("$") || shareName.endsWith("$/")
                        val shareType = if (isHidden) "Hidden Share" else "Share"
                        
                        emit(ToolEvent.Result(OsintResult("SMB $shareType", shareName, target)))
                        emit(ToolEvent.Log("  - $shareName"))
                    }
                }
            } catch (e: jcifs.smb.SmbAuthException) {
                emit(ToolEvent.Error("SMB Authentication Failed. Null sessions might be disabled.", e))
            } catch (e: Exception) {
                emit(ToolEvent.Error("SMB Connection Error: ${e.message}", e))
            }
        }
        emit(ToolEvent.ChainSuggestion("hydra_termux", mapOf("target" to target, "service" to "smb")))
        emit(ToolEvent.Done)
    }
}
