/* repo_view/reorder.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::commit_log_view::CommitLogViewMsg;
use crate::git;

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

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

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

            ReorderAction::DirtyChecked { new_order, summary } => {
                if summary.is_dirty() {
                    let order_for_stash = new_order.clone();
                    self.open_rewrite_stash_choice_dialog(
                        gettext(
                            "You have uncommitted changes. They must be stashed before the commits can be reordered.",
                        ),
                        summary,
                        sender,
                        root,
                        move |flags| {
                            RepoViewMsg::Reorder(ReorderAction::StashChoiceMade {
                                new_order: order_for_stash.clone(),
                                flags,
                            })
                        },
                        || RepoViewMsg::Reorder(ReorderAction::StashChoiceCancelled),
                    );
                } else {
                    self.run_reorder(new_order, false, sender);
                }
            }

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

            ReorderAction::StashChoiceMade { new_order, 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::Reorder(ReorderAction::StashPushed { new_order, result })
                });
            }

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

                match result {
                    Ok(()) => {
                        self.run_reorder(new_order, true, sender);
                    }

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

            ReorderAction::OperationComplete { result, stashed } => {
                let toast = rewrite_outcome_toast(
                    &result,
                    stashed,
                    RewriteToastLabels {
                        completed: &gettext("Commits reordered"),
                        completed_with_stash: &gettext("Commits reordered, stashed changes preserved"),
                        paused_no_conflicts: &gettext("Rebase paused unexpectedly, click Continue Rebase to proceed"),
                        paused_no_conflicts_with_stash: &gettext(
                            "Rebase paused unexpectedly, click Continue Rebase to proceed",
                        ),
                    },
                );

                if !matches!(result, Ok(git::RebaseOutcome::Completed { .. })) {
                    self.commit_log_view.emit(CommitLogViewMsg::ReorderFailed);
                }

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

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

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

    fn run_reorder(&self, new_order: Vec<String>, stashed: bool, sender: &ComponentSender<Self>) {
        let path = self.path.clone();
        let git_command = crate::preferences::git_command();

        sender.spawn_oneshot_command(move || {
            let result = git::reorder_commits(&path, &git_command, &new_order);
            RepoViewMsg::Reorder(ReorderAction::OperationComplete { result, stashed })
        });
    }
}
