package com.optix.android.ui.components

import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ContentCopy
import androidx.compose.material.icons.filled.Share
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalClipboardManager
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.optix.android.domain.model.*
import com.optix.android.ui.theme.*

/** A contextual follow-up tool pre-targeted at an entity found in a result. */
data class ResultAction(
    val label: String,
    val toolSlug: String,
    val params: Map<String, String>,
)

private val IP_REGEX = Regex("""\b(?:\d{1,3}\.){3}\d{1,3}\b""")

/**
 * Inspect a parsed result and return a small list of logical follow-up actions,
 * each pre-targeted at the host/port/service in the result. Kept simple: detect
 * the relevant entity (IP / port / URL) and map it to the matching tool + params.
 */
fun suggestedActionsFor(result: Any): List<ResultAction> {
    val actions = mutableListOf<ResultAction>()

    fun addForPort(ip: String?, port: Int) {
        if (ip.isNullOrBlank()) return
        when (port) {
            22 -> actions += ResultAction("SSH Audit", "ssh_audit", mapOf("target" to ip))
            80, 8080, 8000 -> actions += ResultAction("HTTP Inspect", "http_inspector", mapOf("url" to "http://$ip:$port"))
            443, 8443 -> actions += ResultAction("HTTP Inspect", "http_inspector", mapOf("url" to "https://$ip:$port"))
        }
    }

    when (result) {
        is HostResult -> {
            val ip = result.ip.takeIf { it.isNotBlank() }
            if (ip != null) {
                if (result.openPorts.isEmpty()) {
                    actions += ResultAction("Port Scan", "port_scanner", mapOf("target" to ip))
                }
                actions += ResultAction("Nmap", "nmap_termux", mapOf("target" to ip))
                result.openPorts.take(3).forEach { addForPort(ip, it) }
            }
        }
        is PortResult -> {
            // PortResult has no IP; recover one from the surrounding text.
            val ip = IP_REGEX.find(result.service)?.value
            if (result.state.contains("open", true)) addForPort(ip, result.port)
        }
        else -> {
            // Fallback: sniff a URL or IP out of the string form.
            val text = result.toString()
            val url = Regex("""https?://[\w./:?=&%-]+""").find(text)?.value
            if (url != null) {
                actions += ResultAction("HTTP Inspect", "http_inspector", mapOf("url" to url))
                actions += ResultAction("Nuclei", "nuclei_termux", mapOf("target" to url))
            } else {
                IP_REGEX.find(text)?.value?.let { ip ->
                    actions += ResultAction("Port Scan", "port_scanner", mapOf("target" to ip))
                    actions += ResultAction("Nmap", "nmap_termux", mapOf("target" to ip))
                }
            }
        }
    }
    return actions.distinctBy { it.label }.take(3)
}

@Composable
fun ResultCard(
    result: Any,
    modifier: Modifier = Modifier,
    onExport: (String) -> Unit = {},
    onAction: (ResultAction) -> Unit = {},
) {
    var showHint by remember { mutableStateOf(false) }
    val shape = RoundedCornerShape(6.dp)
    val clipboardManager = LocalClipboardManager.current

    Column(
        modifier = modifier
            .fillMaxWidth()
            .background(T.surfaceVar.copy(alpha = 0.5f), shape)
            .border(1.dp, T.border.copy(alpha = 0.3f), shape)
            .padding(horizontal = 12.dp, vertical = 8.dp),
        verticalArrangement = Arrangement.spacedBy(2.dp),
    ) {
        Row(
            modifier = Modifier.fillMaxWidth(),
            horizontalArrangement = Arrangement.End,
            verticalAlignment = Alignment.CenterVertically
        ) {
            val textToExport = when (result) {
                is HostResult -> "${result.ip} (${result.status}) ports: ${result.openPorts.joinToString(",")}"
                is PortResult -> "${result.port}/${result.protocol} ${result.state} ${result.service}"
                is OpenPort -> "${result.host} ${result.port}/${result.protocol} ${result.state} ${result.service}${result.product?.let { " $it" } ?: ""}${result.version?.let { " $it" } ?: ""}"
                is ServiceInfo -> "${result.host}${result.port?.let { ":$it" } ?: ""} ${result.service} ${result.product ?: ""} ${result.version ?: ""}".trim()
                is VulnerabilityFinding -> "[${result.severity}] ${result.title} (${result.target}) ${result.reference ?: ""}".trim()
                is DnsRecord -> "${result.type}: ${result.value}"
                is OsintResult -> "${result.field}: ${result.value}"
                is VulnResult -> "${result.cveId} (${result.severity}) ${result.description}"
                is SubdomainResult -> "${result.subdomain} (${result.ip})"
                is DirectoryResult -> "${result.path} (${result.status})"
                is HashResult -> "${result.algorithm}: ${result.hash} -> ${result.plaintext ?: "unknown"}"
                else -> result.toString()
            }

            IconButton(
                onClick = { onExport(textToExport) },
                modifier = Modifier.size(24.dp)
            ) {
                Icon(
                    Icons.Default.Share,
                    contentDescription = "Share",
                    tint = T.onSurfaceMid,
                    modifier = Modifier.size(14.dp)
                )
            }
            
            IconButton(
                onClick = { clipboardManager.setText(AnnotatedString(textToExport)) },
                modifier = Modifier.size(24.dp)
            ) {
                Icon(
                    Icons.Default.ContentCopy,
                    contentDescription = "Copy",
                    tint = T.onSurfaceMid,
                    modifier = Modifier.size(14.dp)
                )
            }
        }

        when (result) {
            is HostResult -> {
                Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) {
                    Text(result.ip, color = T.textAccent, style = MaterialTheme.typography.bodyMedium)
                    StatusBadge(result.status, if (result.status.contains("up", true)) T.success else T.onSurfaceMid)
                }
                if (!result.hostname.isNullOrEmpty()) KvRow("Hostname", result.hostname)
                if (result.openPorts.isNotEmpty()) KvRow("Open Ports", result.openPorts.joinToString(", "))
                if (result.latencyMs > 0) KvRow("Latency", "${result.latencyMs}ms")
                LearnMore(showHint, { showHint = !showHint },
                    hint = buildString {
                        append("This device is live on the network. ")
                        if (result.openPorts.isNotEmpty()) {
                            append("Open ports: ")
                            result.openPorts.forEach { p ->
                                val name = when(p) { 22 -> "SSH (remote login)" 80 -> "HTTP web server" 443 -> "HTTPS web server" 21 -> "FTP file transfer" 3389 -> "RDP remote desktop" 445 -> "SMB file sharing" 3306 -> "MySQL database" else -> "port $p" }
                                append("$name. ")
                            }
                        } else {
                            append("No standard ports responded.")
                        }
                    }
                )
            }
            is PortResult -> {
                Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) {
                    Text("${result.port}/${result.protocol}", color = T.textAccent, style = MaterialTheme.typography.bodyMedium)
                    StatusBadge(result.state, if (result.state.contains("open", true)) T.success else T.warning)
                }
                KvRow("Service", result.service)
                LearnMore(showHint, { showHint = !showHint },
                    hint = "Port ${result.port} is ${result.state} and running ${result.service}."
                )
            }
            is VulnResult -> {
                Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) {
                    Text(result.cveId, color = T.warning, style = MaterialTheme.typography.bodyMedium)
                    StatusBadge(result.severity, severityColor(result.severity))
                }
                Text(result.description.take(120), color = T.onSurface, style = MaterialTheme.typography.bodySmall)
                KvRow("CVSS", result.cvss.toString())
            }
            is VulnerabilityFinding -> {
                Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) {
                    Text(result.title, color = T.warning, style = MaterialTheme.typography.bodyMedium)
                    StatusBadge(result.severity.name, severityColor(result.severity.name))
                }
                if (result.detail.isNotBlank()) {
                    Text(result.detail.take(160), color = T.onSurface, style = MaterialTheme.typography.bodySmall)
                }
                KvRow("Target", result.target)
                result.reference?.takeIf { it.isNotBlank() }?.let { KvRow("Ref", it) }
                if (result.cvss > 0) KvRow("CVSS", result.cvss.toString())
            }
            is OpenPort -> {
                Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) {
                    Text("${result.port}/${result.protocol}", color = T.textAccent, style = MaterialTheme.typography.bodyMedium)
                    StatusBadge(result.state, if (result.state.contains("open", true)) T.success else T.warning)
                }
                KvRow("Host", result.host)
                KvRow("Service", result.service)
                val versionLabel = listOfNotNull(result.product, result.version).joinToString(" ")
                if (versionLabel.isNotBlank()) KvRow("Version", versionLabel)
            }
            is ServiceInfo -> {
                Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) {
                    Text(result.service, color = T.textAccent, style = MaterialTheme.typography.bodyMedium)
                    result.port?.let { StatusBadge("port $it", T.accent) }
                }
                KvRow("Host", result.host)
                val versionLabel = listOfNotNull(result.product, result.version).joinToString(" ")
                if (versionLabel.isNotBlank()) KvRow("Version", versionLabel)
                result.banner?.takeIf { it.isNotBlank() }?.let { KvRow("Banner", it.take(80)) }
            }
            is DirectoryResult -> {
                Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) {
                    Text(result.path, color = T.onSurface, style = MaterialTheme.typography.bodySmall)
                    StatusBadge(result.status.toString(), httpStatusColor(result.status))
                }
            }
            is HashResult -> {
                KvRow("Hash", result.hash)
                KvRow("Algorithm", result.algorithm)
                result.plaintext?.let { KvRow("Plaintext", it) }
            }
            else -> {
                Text(result.toString(), color = T.onSurface, style = MaterialTheme.typography.bodySmall)
            }
        }

        val actions = remember(result) { suggestedActionsFor(result) }
        if (actions.isNotEmpty()) {
            Spacer(Modifier.height(4.dp))
            Row(horizontalArrangement = Arrangement.spacedBy(6.dp)) {
                actions.forEach { action ->
                    Text(
                        text = "▶ ${action.label}",
                        color = T.accent,
                        style = MaterialTheme.typography.labelSmall,
                        modifier = Modifier
                            .background(T.accent.copy(alpha = 0.1f), RoundedCornerShape(4.dp))
                            .border(1.dp, T.accent.copy(alpha = 0.4f), RoundedCornerShape(4.dp))
                            .clickable { onAction(action) }
                            .padding(horizontal = 8.dp, vertical = 4.dp),
                    )
                }
            }
        }
    }
}

@Composable
private fun LearnMore(isExpanded: Boolean, onToggle: () -> Unit, hint: String) {
    Spacer(Modifier.height(4.dp))
    Text(
        text = if (isExpanded) "▲ hide explanation" else "ℹ️ what does this mean?",
        color = T.accent.copy(alpha = 0.8f),
        fontSize = 11.sp,
        modifier = Modifier.clickable(onClick = onToggle),
    )
    AnimatedVisibility(visible = isExpanded) {
        Text(
            text = hint,
            color = T.onSurfaceMid,
            fontSize = 12.sp,
            lineHeight = 17.sp,
            modifier = Modifier.padding(top = 4.dp),
        )
    }
}

@Composable
private fun KvRow(key: String, value: String) {
    Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
        Text("$key:", color = T.onSurfaceMid, style = MaterialTheme.typography.bodySmall)
        Text(value, color = T.onSurface, style = MaterialTheme.typography.bodySmall)
    }
}

@Composable
fun StatusBadge(
    label: String,
    color: Color = T.accent,
) {
    Text(
        text  = label,
        color = color,
        style = MaterialTheme.typography.labelSmall,
        modifier = Modifier
            .background(color.copy(alpha = 0.12f), RoundedCornerShape(4.dp))
            .padding(horizontal = 6.dp, vertical = 2.dp),
    )
}

@Composable
private fun severityColor(severity: String) = when (severity.uppercase()) {
    "CRITICAL" -> T.warning
    "HIGH"     -> T.warning
    "MEDIUM"   -> T.accent
    else       -> T.success
}

@Composable
private fun httpStatusColor(status: Int) = when {
    status in 200..299 -> T.success
    status in 300..399 -> T.accent
    status >= 400      -> T.warning
    else               -> T.onSurfaceMid
}
