use crate::commands::invoke::InvokeCommand;
use crate::error::Error;
use crate::function::Function;
use crate::runner::Runner;
use crate::writer::Writer;

pub(crate) struct InvokeRunner<'a> {
    pub(crate) command: InvokeCommand,
    pub(crate) writer: &'a Writer,
}

impl Runner for InvokeRunner<'_> {
    /// Invoke the function either locally or remotely
    async fn run(&mut self) -> Result<(), Error> {
        let project = self.project(&self.command.project).await?;

        // Get function names as well as pull all updates from the code.
        let all_functions = project.parse(std::slice::from_ref(&self.command.name))?;

        let function = Function::find_by_name(&all_functions, &self.command.name)?;

        // If --with_migrations was not passed, or comes with default "" value, then
        // do not set the migrations path. There is a default value set down the flow.
        let migrations_path = if self
            .command
            .with_migrations
            .clone()
            .unwrap_or_default()
            .is_empty()
        {
            None
        } else {
            self.command.with_migrations.clone()
        };

        if !self.command.remote {
            self.local(&function, migrations_path.as_deref()).await?
        } else {
            self.remote(&function).await?
        }

        Ok(())
    }
}
