//! Rhai wrappers for SSH module functions
//!
//! This module provides Rhai wrappers for SSH operations including:
//! - Connection management with builder pattern
//! - Remote command execution
//! - SSH connectivity testing
//! - File transfer operations with rsync
//!
//! All SSH functions are prefixed with `ssh_` to avoid naming conflicts.
//!
//! ## SSH Connection Builder
//! - `ssh_builder()` - Create a new SSH connection builder
//!
//! ## SshConnection Methods (after `.build()`)
//! - `execute(cmd)` - Execute command and return (exit_code, output)
//! - `ping()` - Test SSH connectivity (returns bool)
//! - `file_transfer()` - Create a FileTransferBuilder for rsync operations
//!
//! ## FileTransferBuilder Methods
//! - `archive(bool)` - Preserve permissions and times (-a flag)
//! - `verbose(bool)` - Enable verbose output (-v flag)
//! - `compress(bool)` - Compress during transfer (-z flag)
//! - `delete(bool)` - Delete remote files not in source
//! - `exclude(pattern)` - Add single exclude pattern
//! - `exclude_patterns(vec![...])` - Add multiple exclude patterns
//! - `push(local, remote)` - Upload files to remote
//! - `pull(remote, local)` - Download files from remote

use crate::net::ssh::{FileTransferBuilder, SshConnection, SshConnectionBuilder};
use rhai::{Array, Dynamic, Engine, EvalAltResult};
use std::path::PathBuf;

/// Rhai wrapper for SshConnection
#[derive(Clone)]
pub struct SshConnectionRhai {
    conn: SshConnection,
}

impl SshConnectionRhai {
    /// Create a new Rhai SSH connection wrapper
    pub fn new(conn: SshConnection) -> Self {
        Self { conn }
    }

    /// Get the underlying connection
    pub fn inner(&self) -> &SshConnection {
        &self.conn
    }

    /// Execute a command over SSH
    pub fn execute(&self, command: &str) -> Result<Dynamic, Box<EvalAltResult>> {
        match self.conn.execute(command) {
            Ok((code, output)) => {
                let mut map = rhai::Map::new();
                map.insert("code".into(), Dynamic::from(code));
                map.insert("output".into(), Dynamic::from(output));
                Ok(Dynamic::from(map))
            }
            Err(e) => Err(format!("SSH execute error: {}", e).into()),
        }
    }

    /// Test SSH connectivity
    pub fn ping(&self) -> Result<bool, Box<EvalAltResult>> {
        match self.conn.ping() {
            Ok(success) => Ok(success),
            Err(e) => Err(format!("SSH ping error: {}", e).into()),
        }
    }

    /// Get the host
    pub fn host(&self) -> String {
        self.conn.host().to_string()
    }

    /// Get the port
    pub fn port(&self) -> i64 {
        self.conn.port() as i64
    }

    /// Get the user
    pub fn user(&self) -> String {
        self.conn.user().to_string()
    }

    /// Get the timeout in seconds
    pub fn timeout_secs(&self) -> i64 {
        self.conn.timeout().as_secs() as i64
    }

    /// Create a file transfer builder
    pub fn file_transfer(&self) -> FileTransferBuilderRhai {
        FileTransferBuilderRhai::new(self.conn.file_transfer())
    }
}

/// Rhai wrapper for FileTransferBuilder
#[derive(Clone)]
pub struct FileTransferBuilderRhai {
    builder: FileTransferBuilder,
}

impl FileTransferBuilderRhai {
    /// Create a new Rhai file transfer builder wrapper
    pub fn new(builder: FileTransferBuilder) -> Self {
        Self { builder }
    }

    /// Enable/disable archive mode
    pub fn archive(mut self, enable: bool) -> Self {
        self.builder = self.builder.archive(enable);
        self
    }

    /// Enable/disable verbose output
    pub fn verbose(mut self, enable: bool) -> Self {
        self.builder = self.builder.verbose(enable);
        self
    }

    /// Enable/disable compression
    pub fn compress(mut self, enable: bool) -> Self {
        self.builder = self.builder.compress(enable);
        self
    }

    /// Enable/disable deletion sync
    pub fn delete(mut self, enable: bool) -> Self {
        self.builder = self.builder.delete(enable);
        self
    }

    /// Add a single exclude pattern
    pub fn exclude(mut self, pattern: &str) -> Self {
        self.builder = self.builder.exclude(pattern);
        self
    }

    /// Add multiple exclude patterns from array
    pub fn exclude_patterns(mut self, patterns: Array) -> Self {
        let pattern_strs: Vec<String> = patterns
            .iter()
            .filter_map(|v| {
                if let Some(s) = v.clone().try_cast::<String>() {
                    Some(s)
                } else if let Ok(s) = v.clone().into_string() {
                    Some(s)
                } else {
                    None
                }
            })
            .collect();
        self.builder = self.builder.exclude_patterns(pattern_strs);
        self
    }

    /// Push (upload) files to remote
    pub fn push(&self, local_path: &str, remote_path: &str) -> Result<Dynamic, Box<EvalAltResult>> {
        match self.builder.push(local_path, remote_path) {
            Ok((code, output)) => {
                let mut map = rhai::Map::new();
                map.insert("code".into(), Dynamic::from(code));
                map.insert("output".into(), Dynamic::from(output));
                Ok(Dynamic::from(map))
            }
            Err(e) => Err(format!("SSH push error: {}", e).into()),
        }
    }

    /// Pull (download) files from remote
    pub fn pull(&self, remote_path: &str, local_path: &str) -> Result<Dynamic, Box<EvalAltResult>> {
        match self.builder.pull(remote_path, local_path) {
            Ok((code, output)) => {
                let mut map = rhai::Map::new();
                map.insert("code".into(), Dynamic::from(code));
                map.insert("output".into(), Dynamic::from(output));
                Ok(Dynamic::from(map))
            }
            Err(e) => Err(format!("SSH pull error: {}", e).into()),
        }
    }
}

/// Rhai wrapper for SshConnectionBuilder
#[derive(Clone)]
pub struct SshConnectionBuilderRhai {
    host: String,
    port: u16,
    user: String,
    ssh_private_key_path: Option<PathBuf>,
    timeout_secs: u64,
}

impl SshConnectionBuilderRhai {
    /// Create a new SSH connection builder
    pub fn new() -> Self {
        Self {
            host: "localhost".to_string(),
            port: 22,
            user: "root".to_string(),
            ssh_private_key_path: None,
            timeout_secs: 10,
        }
    }

    /// Set the host
    pub fn host(mut self, host: &str) -> Self {
        self.host = host.to_string();
        self
    }

    /// Set the port
    pub fn port(mut self, port: i64) -> Self {
        self.port = port as u16;
        self
    }

    /// Set the user
    pub fn user(mut self, user: &str) -> Self {
        self.user = user.to_string();
        self
    }

    /// Set the identity file (private key)
    pub fn ssh_private_key_path(mut self, path: &str) -> Self {
        self.ssh_private_key_path = Some(PathBuf::from(path));
        self
    }

    /// Set the timeout in seconds
    pub fn timeout_secs(mut self, secs: i64) -> Self {
        self.timeout_secs = secs as u64;
        self
    }

    /// Build the SSH connection
    pub fn build(self) -> SshConnectionRhai {
        let builder = SshConnectionBuilder::new()
            .host(&self.host)
            .port(self.port)
            .user(&self.user)
            .timeout_secs(self.timeout_secs);

        let builder = if let Some(identity) = self.ssh_private_key_path {
            builder.ssh_private_key_path(identity.to_string_lossy().to_string())
        } else {
            builder
        };

        SshConnectionRhai::new(builder.build())
    }
}

impl Default for SshConnectionBuilderRhai {
    fn default() -> Self {
        Self::new()
    }
}

/// Register SSH module with Rhai engine
pub fn register_ssh_module(engine: &mut Engine) -> Result<(), Box<EvalAltResult>> {
    // Register types
    engine.register_type::<SshConnectionRhai>();
    engine.register_type::<SshConnectionBuilderRhai>();
    engine.register_type::<FileTransferBuilderRhai>();

    // Register builder creation function
    engine.register_fn("ssh_builder", || SshConnectionBuilderRhai::new());

    // Register SshConnectionBuilder methods
    engine.register_fn("host", |builder: SshConnectionBuilderRhai, host: &str| {
        builder.host(host)
    });
    engine.register_fn("port", |builder: SshConnectionBuilderRhai, port: i64| {
        builder.port(port)
    });
    engine.register_fn("user", |builder: SshConnectionBuilderRhai, user: &str| {
        builder.user(user)
    });
    engine.register_fn(
        "ssh_private_key_path",
        |builder: SshConnectionBuilderRhai, path: &str| builder.ssh_private_key_path(path),
    );
    engine.register_fn(
        "timeout_secs",
        |builder: SshConnectionBuilderRhai, secs: i64| builder.timeout_secs(secs),
    );
    engine.register_fn("build", |builder: SshConnectionBuilderRhai| builder.build());

    // Register SshConnection methods
    engine.register_fn("execute", |conn: SshConnectionRhai, cmd: &str| {
        conn.execute(cmd)
    });
    engine.register_fn("ping", |conn: SshConnectionRhai| conn.ping());
    engine.register_fn("host", |conn: SshConnectionRhai| conn.host());
    engine.register_fn("port", |conn: SshConnectionRhai| conn.port());
    engine.register_fn("user", |conn: SshConnectionRhai| conn.user());
    engine.register_fn("timeout_secs", |conn: SshConnectionRhai| {
        conn.timeout_secs()
    });
    engine.register_fn("file_transfer", |conn: SshConnectionRhai| {
        conn.file_transfer()
    });

    // Register FileTransferBuilder methods
    engine.register_fn(
        "archive",
        |builder: FileTransferBuilderRhai, enable: bool| builder.archive(enable),
    );
    engine.register_fn(
        "verbose",
        |builder: FileTransferBuilderRhai, enable: bool| builder.verbose(enable),
    );
    engine.register_fn(
        "compress",
        |builder: FileTransferBuilderRhai, enable: bool| builder.compress(enable),
    );
    engine.register_fn(
        "delete",
        |builder: FileTransferBuilderRhai, enable: bool| builder.delete(enable),
    );
    engine.register_fn(
        "exclude",
        |builder: FileTransferBuilderRhai, pattern: &str| builder.exclude(pattern),
    );
    engine.register_fn(
        "exclude_patterns",
        |builder: FileTransferBuilderRhai, patterns: Array| builder.exclude_patterns(patterns),
    );
    engine.register_fn(
        "push",
        |builder: FileTransferBuilderRhai, local: &str, remote: &str| builder.push(local, remote),
    );
    engine.register_fn(
        "pull",
        |builder: FileTransferBuilderRhai, remote: &str, local: &str| builder.pull(remote, local),
    );

    Ok(())
}
