use anyhow::{Context, Result};
use std::fs;
use std::path::Path;
use tracing::{error, info, warn};

use crate::security::command_guard::SafeCommand;

#[cfg(not(windows))]
const SUDOERS_FILE: &str = "/etc/sudoers.d/gb-protection";

const SUDOERS_CONTENT: &str = r#"# General Bots Security Protection Tools
# This file is managed by botserver install protection
# DO NOT EDIT MANUALLY

# Lynis - security auditing
{user} ALL=(ALL) NOPASSWD: /usr/bin/lynis audit system
{user} ALL=(ALL) NOPASSWD: /usr/bin/lynis audit system --quick
{user} ALL=(ALL) NOPASSWD: /usr/bin/lynis audit system --quick --no-colors
{user} ALL=(ALL) NOPASSWD: /usr/bin/lynis audit system --no-colors

# RKHunter - rootkit detection
{user} ALL=(ALL) NOPASSWD: /usr/bin/rkhunter --check --skip-keypress
{user} ALL=(ALL) NOPASSWD: /usr/bin/rkhunter --check --skip-keypress --report-warnings-only
{user} ALL=(ALL) NOPASSWD: /usr/bin/rkhunter --update

# Chkrootkit - rootkit detection
{user} ALL=(ALL) NOPASSWD: /usr/bin/chkrootkit
{user} ALL=(ALL) NOPASSWD: /usr/bin/chkrootkit -q

# Suricata - IDS/IPS
{user} ALL=(ALL) NOPASSWD: /usr/bin/systemctl start suricata
{user} ALL=(ALL) NOPASSWD: /usr/bin/systemctl stop suricata
{user} ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart suricata
{user} ALL=(ALL) NOPASSWD: /usr/bin/systemctl enable suricata
{user} ALL=(ALL) NOPASSWD: /usr/bin/systemctl disable suricata
{user} ALL=(ALL) NOPASSWD: /usr/bin/systemctl is-active suricata
{user} ALL=(ALL) NOPASSWD: /usr/bin/suricata-update

# ClamAV - antivirus
{user} ALL=(ALL) NOPASSWD: /usr/bin/systemctl start clamav-daemon
{user} ALL=(ALL) NOPASSWD: /usr/bin/systemctl stop clamav-daemon
{user} ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart clamav-daemon
{user} ALL=(ALL) NOPASSWD: /usr/bin/systemctl enable clamav-daemon
{user} ALL=(ALL) NOPASSWD: /usr/bin/systemctl disable clamav-daemon
{user} ALL=(ALL) NOPASSWD: /usr/bin/systemctl is-active clamav-daemon
{user} ALL=(ALL) NOPASSWD: /usr/bin/freshclam

# LMD (Linux Malware Detect)
{user} ALL=(ALL) NOPASSWD: /usr/local/sbin/maldet -a /home
{user} ALL=(ALL) NOPASSWD: /usr/local/sbin/maldet -a /var/www
{user} ALL=(ALL) NOPASSWD: /usr/local/sbin/maldet -a /tmp
{user} ALL=(ALL) NOPASSWD: /usr/local/sbin/maldet --update-sigs
{user} ALL=(ALL) NOPASSWD: /usr/local/sbin/maldet --update-ver
"#;

#[cfg(not(windows))]
const PACKAGES: &[&str] = &[
    "lynis",
    "rkhunter",
    "chkrootkit",
    "suricata",
    "clamav",
    "clamav-daemon",
];

#[cfg(windows)]
const WINDOWS_TOOLS: &[(&str, &str)] = &[
    ("Windows Defender", "MpCmdRun"),
    ("PowerShell", "powershell"),
    ("Windows Firewall", "netsh"),
];

pub struct ProtectionInstaller {
    user: String,
}

impl ProtectionInstaller {
    pub fn new() -> Result<Self> {
        let user = std::env::var("USER").unwrap_or_else(|_| "unknown".to_string());

        Ok(Self { user })
    }

    #[cfg(windows)]
    pub fn check_admin() -> bool {
        let result = SafeCommand::new("powershell")
            .and_then(|cmd| cmd.args(&[
                "-Command",
                "([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)"
            ]))
            .and_then(|cmd| cmd.execute());

        match result {
            Ok(output) => {
                let stdout = String::from_utf8_lossy(&output.stdout);
                stdout.trim() == "True"
            }
            Err(_) => false,
        }
    }

    #[cfg(not(windows))]
    pub fn check_root() -> bool {
        SafeCommand::new("id")
            .and_then(|cmd| cmd.arg("-u"))
            .and_then(|cmd| cmd.execute())
            .map(|o| String::from_utf8_lossy(&o.stdout).trim() == "0")
            .unwrap_or(false)
    }

    pub fn install(&self) -> Result<InstallResult> {
        #[cfg(windows)]
        {
            if !Self::check_admin() {
                return Err(anyhow::anyhow!(
                    "This command requires administrator privileges. Run as Administrator."
                ));
            }
        }

        #[cfg(not(windows))]
        {
            if !Self::check_root() {
                return Err(anyhow::anyhow!(
                    "This command requires root privileges. Run with: sudo botserver install protection"
                ));
            }
        }

        info!(
            "Starting security protection installation for user: {}",
            self.user
        );

        let mut result = InstallResult::default();

        #[cfg(windows)]
        {
            match self.configure_windows_security() {
                Ok(()) => {
                    result
                        .packages_installed
                        .push("Windows Defender".to_string());
                    result
                        .packages_installed
                        .push("Windows Firewall".to_string());
                    info!("Windows security configured successfully");
                }
                Err(e) => {
                    warn!("Windows security configuration had issues: {e}");
                    result
                        .warnings
                        .push(format!("Windows security configuration: {e}"));
                }
            }

            match self.update_windows_signatures() {
                Ok(()) => {
                    result.databases_updated = true;
                    info!("Windows security signatures updated");
                }
                Err(e) => {
                    warn!("Windows signature update failed: {e}");
                    result
                        .warnings
                        .push(format!("Windows signature update: {e}"));
                }
            }
        }

        #[cfg(not(windows))]
        {
            match self.install_packages() {
                Ok(installed) => {
                    result.packages_installed = installed;
                    info!("Packages installed: {:?}", result.packages_installed);
                }
                Err(e) => {
                    error!("Failed to install packages: {e}");
                    result
                        .errors
                        .push(format!("Package installation failed: {e}"));
                }
            }

            match self.create_sudoers() {
                Ok(()) => {
                    result.sudoers_created = true;
                    info!("Sudoers file created successfully");
                }
                Err(e) => {
                    error!("Failed to create sudoers file: {e}");
                    result.errors.push(format!("Sudoers creation failed: {e}"));
                }
            }

            match self.install_lmd() {
                Ok(installed) => {
                    if installed {
                        result.packages_installed.push("maldetect".to_string());
                        info!("LMD (maldetect) installed successfully");
                    }
                }
                Err(e) => {
                    warn!("LMD installation skipped: {e}");
                    result
                        .warnings
                        .push(format!("LMD installation skipped: {e}"));
                }
            }

            match self.update_databases() {
                Ok(()) => {
                    result.databases_updated = true;
                    info!("Security databases updated");
                }
                Err(e) => {
                    warn!("Database update failed: {e}");
                    result.warnings.push(format!("Database update failed: {e}"));
                }
            }
        }

        result.success = result.errors.is_empty();
        Ok(result)
    }

    #[cfg(not(windows))]
    fn install_packages(&self) -> Result<Vec<String>> {
        info!("Updating package lists...");

        SafeCommand::new("apt-get")?
            .arg("update")?
            .execute()
            .context("Failed to update package lists")?;

        let mut installed = Vec::new();

        for package in PACKAGES {
            info!("Installing package: {package}");

            let result = SafeCommand::new("apt-get")?
                .arg("install")?
                .arg("-y")?
                .arg(package)?
                .execute();

            match result {
                Ok(output) => {
                    if output.status.success() {
                        installed.push((*package).to_string());
                    } else {
                        let stderr = String::from_utf8_lossy(&output.stderr);
                        warn!("Package {package} installation had issues: {stderr}");
                    }
                }
                Err(e) => {
                    warn!("Failed to install {package}: {e}");
                }
            }
        }

        Ok(installed)
    }

    #[cfg(windows)]
    fn configure_windows_security(&self) -> Result<()> {
        info!("Configuring Windows security settings...");

        let _ = SafeCommand::new("powershell")
            .and_then(|cmd| cmd.args(&[
                "-Command",
                "Set-MpPreference -DisableRealtimeMonitoring $false; Set-MpPreference -DisableIOAVProtection $false; Set-MpPreference -DisableScriptScanning $false"
            ]))
            .and_then(|cmd| cmd.execute());

        let _ = SafeCommand::new("netsh")
            .and_then(|cmd| cmd.args(&["advfirewall", "set", "allprofiles", "state", "on"]))
            .and_then(|cmd| cmd.execute());

        let _ = SafeCommand::new("powershell")
            .and_then(|cmd| cmd.args(&[
                "-Command",
                "Set-MpPreference -DisableRemovableDriveScanning $false -DisableScanningMappedNetworkDrivesForFullScan $false"
            ]))
            .and_then(|cmd| cmd.execute());

        info!("Windows security configuration completed");
        Ok(())
    }

    #[cfg(not(windows))]
    fn create_sudoers(&self) -> Result<()> {
        use std::os::unix::fs::PermissionsExt;

        let content = SUDOERS_CONTENT.replace("{user}", &self.user);

        info!("Creating sudoers file at {SUDOERS_FILE}");

        fs::write(SUDOERS_FILE, &content).context("Failed to write sudoers file")?;

        let permissions = fs::Permissions::from_mode(0o440);
        fs::set_permissions(SUDOERS_FILE, permissions)
            .context("Failed to set sudoers file permissions")?;

        self.validate_sudoers()?;

        info!("Sudoers file created and validated");
        Ok(())
    }

    #[cfg(not(windows))]
    fn validate_sudoers(&self) -> Result<()> {
        let output = SafeCommand::new("visudo")
            .and_then(|cmd| cmd.args(&["-c", "-f", SUDOERS_FILE]))
            .and_then(|cmd| cmd.execute())
            .context("Failed to run visudo validation")?;

        if !output.status.success() {
            let stderr = String::from_utf8_lossy(&output.stderr);
            fs::remove_file(SUDOERS_FILE).ok();
            return Err(anyhow::anyhow!("Invalid sudoers file syntax: {stderr}"));
        }

        Ok(())
    }

    #[cfg(not(windows))]
    fn install_lmd(&self) -> Result<bool> {
        let maldet_path = Path::new("/usr/local/sbin/maldet");
        if maldet_path.exists() {
            info!("LMD already installed");
            return Ok(false);
        }

        info!("Installing Linux Malware Detect (LMD)...");

        let temp_dir = "/tmp/maldetect_install";
        fs::create_dir_all(temp_dir).ok();

        let download_result = SafeCommand::new("curl")?
            .arg("-sL")?
            .arg("-o")?
            .arg("/tmp/maldetect-current.tar.gz")?
            .arg("https://www.rfxn.com/downloads/maldetect-current.tar.gz")?
            .execute();

        if download_result.is_err() {
            return Err(anyhow::anyhow!("Failed to download LMD"));
        }

        SafeCommand::new("tar")?
            .arg("-xzf")?
            .arg("/tmp/maldetect-current.tar.gz")?
            .arg("-C")?
            .arg(temp_dir)?
            .execute()
            .context("Failed to extract LMD archive")?;

        let entries = fs::read_dir(temp_dir)?;
        let mut install_dir = None;

        for entry in entries.flatten() {
            let path = entry.path();
            if path.is_dir()
                && path
                    .file_name()
                    .is_some_and(|n| n.to_string_lossy().starts_with("maldetect"))
            {
                install_dir = Some(path);
                break;
            }
        }

        let install_dir =
            install_dir.ok_or_else(|| anyhow::anyhow!("LMD install directory not found"))?;
        let install_script = install_dir.join("install.sh");

        if !install_script.exists() {
            return Err(anyhow::anyhow!("LMD install.sh not found"));
        }

        SafeCommand::new("bash")?
            .arg("-c")?
            .shell_script_arg(&format!("cd {} && ./install.sh", install_dir.display()))?
            .execute()
            .context("Failed to run LMD installer")?;

        fs::remove_dir_all(temp_dir).ok();
        fs::remove_file("/tmp/maldetect-current.tar.gz").ok();

        Ok(true)
    }

    #[cfg(not(windows))]
    fn update_databases(&self) -> Result<()> {
        info!("Updating security tool databases...");

        if Path::new("/usr/bin/rkhunter").exists() {
            info!("Updating RKHunter database...");
            let result = SafeCommand::new("rkhunter")?.arg("--update")?.execute();
            if let Err(e) = result {
                warn!("RKHunter update failed: {e}");
            }
        }

        if Path::new("/usr/bin/freshclam").exists() {
            info!("Updating ClamAV signatures...");
            let result = SafeCommand::new("freshclam")?.execute();
            if let Err(e) = result {
                warn!("ClamAV update failed: {e}");
            }
        }

        if Path::new("/usr/bin/suricata-update").exists() {
            info!("Updating Suricata rules...");
            let result = SafeCommand::new("suricata-update")?.execute();
            if let Err(e) = result {
                warn!("Suricata update failed: {e}");
            }
        }

        if Path::new("/usr/local/sbin/maldet").exists() {
            info!("Updating LMD signatures...");
            let result = SafeCommand::new("maldet")?.arg("--update-sigs")?.execute();
            if let Err(e) = result {
                warn!("LMD update failed: {e}");
            }
        }

        Ok(())
    }

    #[cfg(windows)]
    fn update_windows_signatures(&self) -> Result<()> {
        info!("Updating Windows Defender signatures...");

        let result = SafeCommand::new("powershell")
            .and_then(|cmd| cmd.args(&[
                "-Command",
                "Update-MpSignature; Write-Host 'Windows Defender signatures updated'",
            ]))
            .and_then(|cmd| cmd.execute());

        match result {
            Ok(output) => {
                if output.status.success() {
                    info!("Windows Defender signatures updated successfully");
                } else {
                    warn!("Windows Defender signature update had issues");
                }
            }
            Err(e) => {
                warn!("Failed to update Windows Defender signatures: {e}");
            }
        }

        Ok(())
    }

    pub fn uninstall(&self) -> Result<UninstallResult> {
        #[cfg(windows)]
        {
            if !Self::check_admin() {
                return Err(anyhow::anyhow!(
                    "This command requires administrator privileges. Run as Administrator."
                ));
            }
        }

        #[cfg(not(windows))]
        {
            if !Self::check_root() {
                return Err(anyhow::anyhow!(
                    "This command requires root privileges. Run with: sudo botserver remove protection"
                ));
            }
        }

        info!("Removing security protection components...");

        let mut result = UninstallResult::default();

        #[cfg(not(windows))]
        {
            if Path::new(SUDOERS_FILE).exists() {
                match fs::remove_file(SUDOERS_FILE) {
                    Ok(()) => {
                        result.sudoers_removed = true;
                        info!("Removed sudoers file");
                    }
                    Err(e) => {
                        result.errors.push(format!("Failed to remove sudoers: {e}"));
                    }
                }
            }

            result.message = "Protection sudoers removed. Packages were NOT uninstalled - remove manually if needed.".to_string();
        }

        #[cfg(windows)]
        {
            result.message = "Windows protection uninstalled. Windows Defender and Firewall settings were not modified - remove manually if needed.".to_string();
        }

        result.success = result.errors.is_empty();
        Ok(result)
    }

    pub fn verify(&self) -> VerifyResult {
        let mut result = VerifyResult::default();

        #[cfg(not(windows))]
        {
            for package in PACKAGES {
                let binary = match *package {
                    "clamav" | "clamav-daemon" => "clamscan",
                    other => other,
                };

                let check = SafeCommand::new("which")
                    .and_then(|cmd| cmd.arg(binary))
                    .and_then(|cmd| cmd.execute());

                let installed = check.map(|o| o.status.success()).unwrap_or(false);
                result.tools.push(ToolVerification {
                    name: (*package).to_string(),
                    installed,
                    sudo_configured: false,
                });
            }

            let maldet_installed = Path::new("/usr/local/sbin/maldet").exists();
            result.tools.push(ToolVerification {
                name: "maldetect".to_string(),
                installed: maldet_installed,
                sudo_configured: false,
            });

            result.sudoers_exists = Path::new(SUDOERS_FILE).exists();

            if result.sudoers_exists {
                if let Ok(content) = fs::read_to_string(SUDOERS_FILE) {
                    for tool in &mut result.tools {
                        tool.sudo_configured = content.contains(&tool.name)
                            || (tool.name == "clamav" && content.contains("clamav-daemon"))
                            || (tool.name == "clamav-daemon" && content.contains("clamav-daemon"));
                    }
                }
            }

            result.all_installed = result
                .tools
                .iter()
                .filter(|t| t.name != "clamav-daemon")
                .all(|t| t.installed);
            result.all_configured = result.sudoers_exists
                && result
                    .tools
                    .iter()
                    .all(|t| t.sudo_configured || !t.installed);
        }

        #[cfg(windows)]
        {
            for (tool_name, tool_cmd) in WINDOWS_TOOLS {
                let check = SafeCommand::new(tool_cmd)
                    .and_then(|cmd| cmd.arg("--version"))
                    .and_then(|cmd| cmd.execute());

                let installed = check.map(|o| o.status.success()).unwrap_or(false);
                result.tools.push(ToolVerification {
                    name: tool_name.to_string(),
                    installed,
                    sudo_configured: true, // Windows tools are typically pre-configured
                });
            }

            result.sudoers_exists = false; // No sudoers on Windows
            result.all_installed = result.tools.iter().all(|t| t.installed);
            result.all_configured = true; // Windows tools are pre-configured
        }

        result
    }
}

impl Default for ProtectionInstaller {
    fn default() -> Self {
        Self::new().unwrap_or(Self {
            user: "unknown".to_string(),
        })
    }
}

#[derive(Default)]
pub struct InstallResult {
    pub success: bool,
    pub packages_installed: Vec<String>,
    pub sudoers_created: bool,
    pub databases_updated: bool,
    pub errors: Vec<String>,
    pub warnings: Vec<String>,
}


impl InstallResult {
    pub fn print(&self) {
        println!("\n=== Security Protection Installation Result ===");
        println!(
            "Status: {}",
            if self.success {
                "✓ SUCCESS"
            } else {
                "✗ FAILED"
            }
        );

        if !self.packages_installed.is_empty() {
            println!("\nInstalled Packages:");
            for pkg in &self.packages_installed {
                println!("  - {pkg}");
            }
        }

        #[cfg(not(windows))]
        {
            println!("\nSudoers Configuration:");
            println!(
                "  - File created: {}",
                if self.sudoers_created { "✓" } else { "✗" }
            );
        }

        println!(
            "\nDatabases Updated: {}",
            if self.databases_updated { "✓" } else { "✗" }
        );

        if !self.warnings.is_empty() {
            println!("\nWarnings:");
            for warning in &self.warnings {
                println!("  ! {warning}");
            }
        }

        if !self.errors.is_empty() {
            println!("\nErrors:");
            for error in &self.errors {
                println!("  ✗ {error}");
            }
        }

        println!("\n");
    }
}

#[derive(Default)]
pub struct UninstallResult {
    pub success: bool,
    pub sudoers_removed: bool,
    pub message: String,
    pub errors: Vec<String>,
}


impl UninstallResult {
    pub fn print(&self) {
        println!("\n=== Security Protection Uninstallation Result ===");
        println!(
            "Status: {}",
            if self.success {
                "✓ SUCCESS"
            } else {
                "✗ FAILED"
            }
        );

        #[cfg(not(windows))]
        {
            println!(
                "Sudoers removed: {}",
                if self.sudoers_removed { "✓" } else { "✗" }
            );
        }

        println!("\nMessage:");
        println!("  {}", self.message);

        if !self.errors.is_empty() {
            println!("\nErrors:");
            for error in &self.errors {
                println!("  ✗ {error}");
            }
        }

        println!("\n");
    }
}

#[derive(Default)]
pub struct VerifyResult {
    pub all_installed: bool,
    pub all_configured: bool,
    pub sudoers_exists: bool,
    pub tools: Vec<ToolVerification>,
}


pub struct ToolVerification {
    pub name: String,
    pub installed: bool,
    pub sudo_configured: bool,
}

impl VerifyResult {
    pub fn print(&self) {
        println!("\n=== Security Protection Verification ===");
        println!(
            "All tools installed: {}",
            if self.all_installed { "✓" } else { "✗" }
        );
        println!(
            "All tools configured: {}",
            if self.all_configured { "✓" } else { "✗" }
        );

        #[cfg(not(windows))]
        {
            println!(
                "Sudoers file exists: {}",
                if self.sudoers_exists { "✓" } else { "✗" }
            );
        }

        println!("\nTool Status:");
        for tool in &self.tools {
            println!(
                "  {} {}: {} {}",
                if tool.installed { "✓" } else { "✗" },
                tool.name,
                if tool.installed {
                    "installed"
                } else {
                    "not installed"
                },
                if tool.sudo_configured {
                    "(configured)"
                } else {
                    "(not configured)"
                }
            );
        }

        println!("\n");
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_install_result_default() {
        let result = InstallResult::default();
        assert!(!result.success);
        assert!(result.packages_installed.is_empty());
        assert!(result.errors.is_empty());
    }

    #[test]
    fn test_verify_result_default() {
        let result = VerifyResult::default();
        assert!(!result.all_installed);
        assert!(!result.all_configured);
        assert!(result.tools.is_empty());
    }

    #[test]
    fn test_tool_verification_default() {
        let tool = ToolVerification {
            name: "test".to_string(),
            installed: false,
            sudo_configured: false,
        };
        assert!(!tool.installed);
        assert!(!tool.sudo_configured);
    }

    #[test]
    fn test_uninstall_result_default() {
        let result = UninstallResult::default();
        assert!(!result.success);
        assert!(result.errors.is_empty());
    }

    #[test]
    fn test_protection_installer_default() {
        let installer = ProtectionInstaller::default();
        assert!(!installer.user.is_empty());
    }

    #[cfg(not(windows))]
    #[test]
    fn test_sudoers_content_has_placeholder() {
        assert!(SUDOERS_CONTENT.contains("{user}"));
    }

    #[cfg(not(windows))]
    #[test]
    fn test_sudoers_content_no_wildcards() {
        // Ensure no dangerous wildcards in sudoers
        assert!(!SUDOERS_CONTENT.contains(" ALL=(ALL) ALL"));
    }

    #[cfg(not(windows))]
    #[test]
    fn test_packages_list() {
        assert!(PACKAGES.len() > 0);
        assert!(PACKAGES.contains(&"lynis"));
        assert!(PACKAGES.contains(&"rkhunter"));
    }

    #[cfg(windows)]
    #[test]
    fn test_windows_tools_list() {
        assert!(WINDOWS_TOOLS.len() > 0);
        assert!(WINDOWS_TOOLS.iter().any(|t| t.0 == "Windows Defender"));
    }
}
