//! Commit commands.
//!
//! Handles committing staged changes with support for amend operations.

use crate::commands::{Command, CommandResult};
use crate::services::GitService;
use crate::app::{AppState, Action, reducer};
use crate::errors::CommandError;
use tracing::instrument;

/// Commit staged changes
pub struct CommitCommand {
    pub message: String,
    pub amend: bool,
    pub author_name: Option<String>,
    pub author_email: Option<String>,
}

impl Command for CommitCommand {
    #[instrument(skip(self, git, state), fields(message = %self.message, amend = self.amend))]
    fn execute(
        &self,
        git: &GitService,
        state: &AppState,
    ) -> Result<CommandResult, CommandError> {
        if self.message.trim().is_empty() {
            let mut new_state = state.clone();
            new_state = reducer(new_state, Action::SetStatusError(Some("Commit message is empty".into())));
            return Ok(CommandResult::StateUpdate(new_state));
        }

        let mut new_state = state.clone();
        new_state = reducer(new_state, Action::SetOpStatus(Some("committing…".into())));
        match git.commit(
            &state.repo_path,
            &self.message,
            self.amend,
            self.author_name.as_deref(),
            self.author_email.as_deref(),
        ) {
            Ok(_) => {
                let label = if self.amend { "Amended" } else { "Committed" };
                new_state = reducer(
                    new_state,
                    Action::SetFeedback(Some(format!("{label} changes"))),
                );
                if self.amend {
                    new_state = reducer(
                        new_state,
                        Action::AppendOpLog("Amend done. Push with --force-with-lease (P) if this branch is shared.".into()),
                    );
                    new_state = reducer(
                        new_state,
                        Action::SetOpStatus(Some("Amend done. Push with --force-with-lease (P) if shared.".into())),
                    );
                }
                new_state = reducer(new_state, Action::SetRefreshing(true));
                new_state.commit_mode = false;
                new_state.commit_input.clear();
                new_state = reducer(new_state, Action::AppendOpLog(format!("{label} {}", self.message)));
            }
            Err(e) => {
                new_state = reducer(new_state, Action::AppendOpLog(format!("commit error: {e}")));
                new_state = reducer(new_state, Action::SetStatusError(Some(format!("commit error: {e}"))));
            }
        }
        new_state = reducer(new_state, Action::SetOpStatus(None));
        Ok(CommandResult::StateUpdate(new_state))
    }
}

