use std::path::{Path, PathBuf};

use serde::{Deserialize, Serialize};

use crate::{
    action::{ActionError, Context},
    action_impl::ActionImpl,
};

/// Create a directory.
///
/// This is meant for internal use by Ambient. It can't be used in any kind
/// of plan, pre-plan, or post-plan. It can be used in a runnable plan.
/// It is generated by Ambient to set up execution of a runnable plan.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Mkdir {
    pathname: PathBuf,
}

impl Mkdir {
    /// Create a new `Mkdir` action.
    pub fn new(pathname: PathBuf) -> Self {
        Self { pathname }
    }

    /// Directory to be created.
    pub fn pathname(&self) -> &Path {
        &self.pathname
    }
}

impl ActionImpl for Mkdir {
    fn execute(&self, _context: &mut Context) -> Result<(), ActionError> {
        if !self.pathname.exists() {
            std::fs::create_dir(&self.pathname)
                .map_err(|e| MkdirError::Mkdir(self.pathname.clone(), e))?;
        }
        Ok(())
    }
}

/// Errors from the Mkdir action
#[derive(Debug, thiserror::Error)]
pub enum MkdirError {
    /// Can't create a directory.
    #[error("failed to create directory {0}")]
    Mkdir(PathBuf, #[source] std::io::Error),
}

impl From<MkdirError> for ActionError {
    fn from(value: MkdirError) -> Self {
        Self::Mkdir(value)
    }
}
