use std::path::PathBuf;

use serde::{Deserialize, Serialize};

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

/// Create a file with content.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct CreateFile {
    filename: PathBuf,
    content: String,
    overwrite: bool,
}

impl CreateFile {
    /// Create a new `create_file` action.
    pub fn new<P: Into<PathBuf>, S: Into<String>>(
        filename: P,
        content: S,
        overwrite: bool,
    ) -> Self {
        Self {
            filename: filename.into(),
            content: content.into(),
            overwrite,
        }
    }
}

impl ActionImpl for CreateFile {
    fn execute(&self, _context: &mut Context) -> Result<(), ActionError> {
        if self.filename.exists() && !self.overwrite {
            Err(CreateFileError::Exits(self.filename.clone()))?;
        } else {
            std::fs::write(&self.filename, self.content.as_bytes())
                .map_err(|err| CreateFileError::Write(self.filename.clone(), err))?;
        }
        Ok(())
    }
}

/// Errors from the Pwd action.
#[derive(Debug, thiserror::Error)]
pub enum CreateFileError {
    /// Already exists.
    #[error("can't create file, as it already exists: {0}")]
    Exits(PathBuf),

    /// Can't write.
    #[error("failed to write file {0}")]
    Write(PathBuf, #[source] std::io::Error),
}

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