/* repo_view/edit_commit.rs
 *
 * Copyright 2026 Christian Kruse
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 *
 * SPDX-License-Identifier: AGPL-3.0-or-later
 */

use gettextrs::gettext;
use relm4::prelude::*;

use super::rewrite_helpers::{RewriteToastLabels, rewrite_outcome_toast};
use super::{RepoView, RepoViewMsg, WorkspaceTab};
use crate::git;

#[derive(Debug)]
pub enum EditCommitAction {
    Requested {
        oid: String,
    },
    DirtyChecked {
        oid: String,
        summary: git::DirtySummary,
    },
    StashChoiceMade {
        oid: String,
        flags: git::StashPushFlags,
    },
    StashChoiceCancelled,
    StashPushed {
        oid: String,
        result: Result<(), String>,
    },
    Confirmed {
        oid: String,
        stashed: bool,
    },
    OperationComplete {
        result: Result<git::RebaseOutcome, String>,
        stashed: bool,
    },
}

impl RepoView {
    pub(super) fn handle_edit_commit_action(
        &mut self,
        action: EditCommitAction,
        sender: &ComponentSender<Self>,
        root: &adw::ToastOverlay,
    ) {
        match action {
            EditCommitAction::Requested { oid } => {
                let repo_path = self.path.clone();

                sender.spawn_oneshot_command(move || match git::dirty_summary(&repo_path) {
                    Ok(summary) => RepoViewMsg::EditCommit(EditCommitAction::DirtyChecked { oid, summary }),
                    Err(msg) => RepoViewMsg::ShowToast(msg),
                });
            }

            EditCommitAction::DirtyChecked { oid, summary } => {
                if summary.is_dirty() {
                    let oid_for_stash = oid.clone();
                    self.open_rewrite_stash_choice_dialog(
                        gettext("You have uncommitted changes. They must be stashed before the commit can be edited."),
                        summary,
                        sender,
                        root,
                        move |flags| {
                            RepoViewMsg::EditCommit(EditCommitAction::StashChoiceMade {
                                oid: oid_for_stash.clone(),
                                flags,
                            })
                        },
                        || RepoViewMsg::EditCommit(EditCommitAction::StashChoiceCancelled),
                    );
                } else {
                    sender.input(RepoViewMsg::EditCommit(EditCommitAction::Confirmed { oid, stashed: false }));
                }
            }

            EditCommitAction::StashChoiceCancelled => {
                self.stash_switch_dialog = None;
            }

            EditCommitAction::StashChoiceMade { oid, flags } => {
                self.stash_switch_dialog = None;
                let repo_path = self.path.clone();

                sender.spawn_oneshot_command(move || {
                    let result = git::stash_push(&repo_path, None, flags);
                    RepoViewMsg::EditCommit(EditCommitAction::StashPushed { oid, result })
                });
            }

            EditCommitAction::StashPushed { oid, result } => {
                sender.input(RepoViewMsg::Refresh);

                match result {
                    Ok(()) => {
                        sender.input(RepoViewMsg::EditCommit(EditCommitAction::Confirmed { oid, stashed: true }));
                    }

                    Err(msg) => {
                        root.add_toast(adw::Toast::new(&msg));
                    }
                }
            }

            EditCommitAction::Confirmed { oid, stashed } => {
                let path = self.path.clone();
                let git_command = crate::preferences::git_command();

                sender.spawn_oneshot_command(move || {
                    let result = git::edit_commit(&path, &git_command, &oid);
                    RepoViewMsg::EditCommit(EditCommitAction::OperationComplete { result, stashed })
                });
            }

            EditCommitAction::OperationComplete { result, stashed } => {
                let toast = rewrite_outcome_toast(
                    &result,
                    stashed,
                    RewriteToastLabels {
                        completed: &gettext("Rebase completed"),
                        completed_with_stash: &gettext("Rebase completed, stashed changes preserved"),
                        paused_no_conflicts: &gettext("Rebase paused, amend the commit, then click Continue Rebase"),
                        paused_no_conflicts_with_stash: &gettext(
                            "Rebase paused, amend the commit, then click Continue Rebase. Stashed changes preserved.",
                        ),
                    },
                );

                root.add_toast(adw::Toast::new(&toast));

                if matches!(result, Ok(git::RebaseOutcome::Paused { .. })) {
                    sender.input(RepoViewMsg::WorkspaceSelected(WorkspaceTab::WorkingCopy));
                }

                sender.input(RepoViewMsg::Refresh);
            }
        }
    }
}
