use log::{debug, error, info, warn};
use std::{fs, path::PathBuf};

pub struct ConfigManager {
    pub configs: Vec<String>,
    config_dir: PathBuf,
    tmux_config_path: PathBuf,
}

impl ConfigManager {
    pub fn new() -> Result<Self, Box<dyn std::error::Error>> {
        debug!("Initializing ConfigManager");

        // Get config directory: ~/.config/tmucks/
        let home = dirs::home_dir().ok_or("Could not find home directory")?;
        let config_dir = home.join(".config").join("tmucks");
        info!("Config directory: {:?}", config_dir);

        // Create config directory if it doesn't exist
        if !config_dir.exists() {
            debug!("Creating config directory: {:?}", config_dir);
            fs::create_dir_all(&config_dir)?;
            info!("Created config directory: {:?}", config_dir);
        }

        // Get tmux config path
        let tmux_config_path = home.join(".tmux.conf");
        debug!("Tmux config path: {:?}", tmux_config_path);

        // Read available configs
        let configs = Self::read_configs(&config_dir)?;
        info!("Loaded {} config(s)", configs.len());

        Ok(Self {
            configs,
            config_dir,
            tmux_config_path,
        })
    }

    fn read_configs(dir: &PathBuf) -> Result<Vec<String>, Box<dyn std::error::Error>> {
        debug!("Reading configs from directory: {:?}", dir);
        let mut configs = Vec::new();

        if dir.exists() {
            for entry in fs::read_dir(dir)? {
                let entry = entry?;
                let path = entry.path();

                if path.is_file() {
                    if let Some(name) = path.file_name() {
                        if let Some(name_str) = name.to_str() {
                            debug!("Found config file: {}", name_str);
                            configs.push(name_str.to_string());
                        }
                    }
                }
            }
        }

        configs.sort();
        debug!("Sorted {} config(s)", configs.len());
        Ok(configs)
    }

    pub fn apply_config(&self, config_name: &str) -> Result<(), Box<dyn std::error::Error>> {
        info!("Applying config: {}", config_name);
        let source_path = self.config_dir.join(config_name);

        if !source_path.exists() {
            error!("Config file not found: {}", config_name);
            return Err(format!("Config file not found: {}", config_name).into());
        }

        debug!("Copying {:?} to {:?}", source_path, self.tmux_config_path);
        // Use cp command to copy the config
        fs::copy(&source_path, &self.tmux_config_path)?;
        info!(
            "Copied config {} to {:?}",
            config_name, self.tmux_config_path
        );

        // Reload tmux config if tmux is running
        if let Some(path_str) = self.tmux_config_path.to_str() {
            debug!("Attempting to reload tmux config");
            let result = std::process::Command::new("tmux")
                .args(["source-file", path_str])
                .output();

            match result {
                Ok(_) => info!("Tmux config reloaded successfully"),
                Err(e) => warn!("Failed to reload tmux config: {}", e),
            }
        }

        info!("Successfully applied config: {}", config_name);
        Ok(())
    }

    pub fn delete_config(&self, config_name: &str) -> Result<(), Box<dyn std::error::Error>> {
        info!("Deleting config: {}", config_name);
        let config_path = self.config_dir.join(config_name);

        if !config_path.exists() {
            error!("Config file not found: {}", config_name);
            return Err(format!("Config file not found: {}", config_name).into());
        }

        debug!("Removing file: {:?}", config_path);
        fs::remove_file(&config_path)?;
        info!("Successfully deleted config: {}", config_name);
        Ok(())
    }

    pub fn save_current_config(&self, config_name: &str) -> Result<(), Box<dyn std::error::Error>> {
        info!("Saving current config as: {}", config_name);

        if !self.tmux_config_path.exists() {
            error!("No tmux config file found at {:?}", self.tmux_config_path);
            return Err("No tmux config file found at ~/.tmux.conf".into());
        }

        let dest_path = self.config_dir.join(config_name);
        debug!("Destination path: {:?}", dest_path);

        // Check if config already exists
        if dest_path.exists() {
            warn!("Config '{}' already exists", config_name);
            return Err(format!(
                "Config '{}' already exists. Use 'update' command to overwrite an existing config.",
                config_name
            )
            .into());
        }

        debug!("Copying {:?} to {:?}", self.tmux_config_path, dest_path);
        fs::copy(&self.tmux_config_path, &dest_path)?;
        info!("Successfully saved config: {}", config_name);

        Ok(())
    }

    pub fn update_config(&self, config_name: &str) -> Result<(), Box<dyn std::error::Error>> {
        info!("Updating config: {}", config_name);

        if !self.tmux_config_path.exists() {
            error!("No tmux config file found at {:?}", self.tmux_config_path);
            return Err("No tmux config file found at ~/.tmux.conf".into());
        }

        let dest_path = self.config_dir.join(config_name);
        debug!("Destination path: {:?}", dest_path);

        // Check if config exists
        if !dest_path.exists() {
            warn!("Config '{}' does not exist", config_name);
            return Err(format!(
                "Config '{}' does not exist. Use 'save' command to create a new config.",
                config_name
            )
            .into());
        }

        // Copy current .tmux.conf to the selected config file (overwriting it)
        debug!(
            "Overwriting {:?} with {:?}",
            dest_path, self.tmux_config_path
        );
        fs::copy(&self.tmux_config_path, &dest_path)?;
        info!("Successfully updated config: {}", config_name);

        Ok(())
    }

    pub fn rename_config(&self, old_name: &str, new_name: &str) -> Result<(), Box<dyn std::error::Error>> {
        info!("Renaming config: {} -> {}", old_name, new_name);

        let old_path = self.config_dir.join(old_name);
        let new_path = self.config_dir.join(new_name);

        if !old_path.exists() {
            error!("Config file not found: {}", old_name);
            return Err(format!("Config file not found: {}", old_name).into());
        }

        if new_path.exists() {
            error!("Config '{}' already exists", new_name);
            return Err(format!("Config '{}' already exists", new_name).into());
        }

        debug!("Renaming {:?} to {:?}", old_path, new_path);
        fs::rename(&old_path, &new_path)?;
        info!("Successfully renamed config: {} -> {}", old_name, new_name);
        Ok(())
    }
}
