//! Cherry-pick and revert commands.
//!
//! Handles applying commits from other branches and reverting commits.

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

/// Cherry-pick a commit
pub struct CherryPickCommand {
    pub hash: String,
}

impl Command for CherryPickCommand {
    #[instrument(skip(self, git, state), fields(hash = %self.hash))]
    fn execute(
        &self,
        git: &GitService,
        state: &AppState,
    ) -> Result<CommandResult, CommandError> {
        let mut new_state = state.clone();
        new_state = reducer(new_state, Action::SetOpStatus(Some("cherry-picking…".into())));
        match git.cherry_pick(&state.repo_path, &self.hash) {
            Ok(_) => {
                new_state = reducer(new_state, Action::SetFeedback(Some(format!("Cherry-picked {}", self.hash))));
                new_state = reducer(
                    new_state,
                    Action::AppendOpLog(
                        "Cherry-pick done. If history was rewritten, push with --force-with-lease (P).".into(),
                    ),
                );
                new_state = reducer(
                    new_state,
                    Action::SetOpStatus(Some(
                        "Cherry-pick done. Push with --force-with-lease (P) if shared.".into(),
                    )),
                );
                new_state = reducer(new_state, Action::SetRefreshing(true));
                new_state = reducer(new_state, Action::AppendOpLog(format!("cherry-pick {}", self.hash)));
            }
            Err(e) => {
                new_state = reducer(new_state, Action::AppendOpLog(format!("cherry-pick error: {e}")));
                new_state = reducer(new_state, Action::SetStatusError(Some(format!("cherry-pick error: {e}"))));
            }
        }
        new_state = reducer(new_state, Action::SetOpStatus(None));
        Ok(CommandResult::StateUpdate(new_state))
    }
}

/// Revert a commit
pub struct RevertCommand {
    pub hash: String,
}

impl Command for RevertCommand {
    #[instrument(skip(self, git, state), fields(hash = %self.hash))]
    fn execute(
        &self,
        git: &GitService,
        state: &AppState,
    ) -> Result<CommandResult, CommandError> {
        let mut new_state = state.clone();
        new_state = reducer(new_state, Action::SetOpStatus(Some("reverting…".into())));
        match git.revert(&state.repo_path, &self.hash) {
            Ok(_) => {
                new_state = reducer(new_state, Action::SetFeedback(Some(format!("Reverted {}", self.hash))));
                new_state = reducer(
                    new_state,
                    Action::AppendOpLog(
                        "Revert done. If history was rewritten, push with --force-with-lease (P).".into(),
                    ),
                );
                new_state = reducer(
                    new_state,
                    Action::SetOpStatus(Some(
                        "Revert done. Push with --force-with-lease (P) if shared.".into(),
                    )),
                );
                new_state = reducer(new_state, Action::SetRefreshing(true));
                new_state = reducer(new_state, Action::AppendOpLog(format!("revert {}", self.hash)));
            }
            Err(e) => {
                new_state = reducer(new_state, Action::AppendOpLog(format!("revert error: {e}")));
                new_state = reducer(new_state, Action::SetStatusError(Some(format!("revert error: {e}"))));
            }
        }
        new_state = reducer(new_state, Action::SetOpStatus(None));
        Ok(CommandResult::StateUpdate(new_state))
    }
}

