//! Error types for CLI commands

use anyhow::Error;
use std::fmt;

/// Result type for command execution
pub type CommandResult<T> = Result<T, CommandError>;

/// Errors that can occur during command execution
#[derive(Debug)]
pub enum CommandError {
    /// Configuration file not found or invalid
    ConfigError(String),

    /// Project not initialized (mecha10.json missing)
    ProjectNotInitialized,

    /// Invalid command arguments
    InvalidArguments(String),

    /// External process failed
    ProcessFailed {
        command: String,
        exit_code: Option<i32>,
        stderr: Option<String>,
    },

    /// User cancelled operation
    Cancelled,

    /// File system operation failed
    IoError(std::io::Error),

    /// Generic error from anyhow
    Other(Error),
}

impl fmt::Display for CommandError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            CommandError::ConfigError(msg) => write!(f, "Configuration error: {}", msg),
            CommandError::ProjectNotInitialized => {
                write!(f, "Project not initialized. Run 'mecha10 init' first.")
            }
            CommandError::InvalidArguments(msg) => write!(f, "Invalid arguments: {}", msg),
            CommandError::ProcessFailed {
                command,
                exit_code,
                stderr,
            } => {
                write!(f, "Process '{}' failed", command)?;
                if let Some(code) = exit_code {
                    write!(f, " with exit code {}", code)?;
                }
                if let Some(err) = stderr {
                    write!(f, "\nError output: {}", err)?;
                }
                Ok(())
            }
            CommandError::Cancelled => write!(f, "Operation cancelled by user"),
            CommandError::IoError(err) => write!(f, "I/O error: {}", err),
            CommandError::Other(err) => write!(f, "{}", err),
        }
    }
}

impl std::error::Error for CommandError {}

impl From<std::io::Error> for CommandError {
    fn from(err: std::io::Error) -> Self {
        CommandError::IoError(err)
    }
}

impl From<anyhow::Error> for CommandError {
    fn from(err: anyhow::Error) -> Self {
        CommandError::Other(err)
    }
}
