/* repo_view/detached_checkout.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 gtk::prelude::*;
use relm4::prelude::*;

use super::{DetachedCheckoutAction, RepoView, RepoViewMsg};
use crate::git;
use crate::stash_switch_dialog::{StashSwitchDialog, StashSwitchDialogInit, StashSwitchDialogOutput};

impl RepoView {
    pub(super) fn handle_detached_checkout(
        &mut self,
        action: DetachedCheckoutAction,
        sender: &ComponentSender<Self>,
        root: &adw::ToastOverlay,
    ) {
        match action {
            DetachedCheckoutAction::CheckoutRequested(target) => {
                let repo_path = self.path.clone();

                sender.spawn_oneshot_command(move || match git::dirty_summary(&repo_path) {
                    Ok(summary) => {
                        RepoViewMsg::DetachedCheckout(DetachedCheckoutAction::DirtyCheckComplete { target, summary })
                    }
                    Err(msg) => RepoViewMsg::ShowToast(msg),
                });
            }

            DetachedCheckoutAction::StashSwitchDialogDismissed => {
                self.stash_switch_dialog = None;
            }

            DetachedCheckoutAction::DirtyCheckComplete { target, summary } => {
                if summary.is_dirty() {
                    let window = root.ancestor(gtk::Window::static_type()).and_downcast::<gtk::Window>();
                    let t = target.clone();

                    self.stash_switch_dialog = Some(
                        StashSwitchDialog::builder()
                            .launch(StashSwitchDialogInit {
                                heading: gettext("Uncommitted Changes"),
                                body: gettext(
                                    "You have uncommitted changes. How do you want to proceed checking out “{}”?",
                                )
                                .replace("{}", &target),
                                proceed_label: gettext("Check Out"),
                                allow_skip_stash: true,
                                has_tracked_changes: summary.has_tracked_changes,
                                has_untracked: summary.has_untracked,
                                parent_window: window,
                            })
                            .forward(sender.input_sender(), move |output| match output {
                                StashSwitchDialogOutput::ProceedWithoutStash => RepoViewMsg::DetachedCheckout(
                                    DetachedCheckoutAction::CheckoutWithoutStash(t.clone()),
                                ),

                                StashSwitchDialogOutput::StashTrackedOnly => RepoViewMsg::DetachedCheckout(
                                    DetachedCheckoutAction::StashAndCheckout(t.clone(), git::StashPushFlags::Default),
                                ),

                                StashSwitchDialogOutput::StashWithUntracked => {
                                    RepoViewMsg::DetachedCheckout(DetachedCheckoutAction::StashAndCheckout(
                                        t.clone(),
                                        git::StashPushFlags::IncludeUntracked,
                                    ))
                                }

                                StashSwitchDialogOutput::Cancelled => {
                                    RepoViewMsg::DetachedCheckout(DetachedCheckoutAction::StashSwitchDialogDismissed)
                                }
                            }),
                    );
                } else {
                    let repo_path = self.path.clone();

                    sender.spawn_oneshot_command(move || {
                        let result = git::checkout_detached(&repo_path, &target);
                        RepoViewMsg::DetachedCheckout(DetachedCheckoutAction::CheckoutComplete(result))
                    });
                }
            }

            DetachedCheckoutAction::CheckoutWithoutStash(target) => {
                self.stash_switch_dialog = None;
                let repo_path = self.path.clone();

                sender.spawn_oneshot_command(move || {
                    let result = git::checkout_detached(&repo_path, &target);
                    RepoViewMsg::DetachedCheckout(DetachedCheckoutAction::CheckoutComplete(result))
                });
            }

            DetachedCheckoutAction::StashAndCheckout(target, flags) => {
                self.stash_switch_dialog = None;
                let repo_path = self.path.clone();

                sender.spawn_oneshot_command(move || {
                    if let Err(e) = git::stash_push(&repo_path, None, flags) {
                        return RepoViewMsg::DetachedCheckout(DetachedCheckoutAction::CheckoutComplete(Err(e)));
                    }

                    let result = git::checkout_detached(&repo_path, &target);
                    RepoViewMsg::DetachedCheckout(DetachedCheckoutAction::CheckoutComplete(result))
                });
            }

            DetachedCheckoutAction::CheckoutComplete(result) => {
                let toast = match result {
                    Ok(()) => gettext("Checked out (detached HEAD)"),
                    Err(msg) => msg,
                };

                root.add_toast(adw::Toast::new(&toast));
                sender.input(RepoViewMsg::Refresh);
            }
        }
    }
}
