/* repo_view/push.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 adw::prelude::*;
use gettextrs::gettext;
use relm4::prelude::*;

use super::{RepoView, RepoViewMsg, RepoViewOutput};
use crate::push_dialog::{PushDialog, PushDialogInit, PushDialogOutput};
use crate::{git, preferences};

impl RepoView {
    pub(super) fn handle_push_message(
        &mut self,
        msg: RepoViewMsg,
        sender: &ComponentSender<RepoView>,
        root: &adw::ToastOverlay,
    ) {
        match msg {
            RepoViewMsg::Push => {
                let path = self.path.clone();

                sender.spawn_oneshot_command(move || {
                    RepoViewMsg::PushDefaultsLoaded(git::get_push_defaults(&path, None))
                });
            }

            RepoViewMsg::PushDefaultsLoaded(result) => match result {
                Ok(defaults) => {
                    let window = root.ancestor(gtk::Window::static_type()).and_downcast::<gtk::Window>();

                    self.push_dialog = Some(
                        PushDialog::builder()
                            .launch(PushDialogInit {
                                defaults,
                                parent_window: window,
                            })
                            .forward(sender.input_sender(), |output| match output {
                                PushDialogOutput::Confirmed(settings) => RepoViewMsg::PushConfirmed(settings),
                                PushDialogOutput::Cancelled => RepoViewMsg::PushDialogDismissed,
                            }),
                    );
                }

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

            RepoViewMsg::PushDialogDismissed => {
                self.push_dialog = None;
            }

            RepoViewMsg::PushConfirmed(settings) => {
                self.push_dialog = None;

                if self.remote_op_in_progress {
                    return;
                }

                self.remote_op_in_progress = true;
                sender.output(RepoViewOutput::RemoteOpStarted).ok();

                let path = self.path.clone();
                let git_command = preferences::git_command();

                sender.spawn_oneshot_command(move || {
                    let result = git::push(
                        &path,
                        git::PushOptions {
                            remote_name: settings.remote.clone(),
                            local_branch: settings.local_branch,
                            remote_branch: settings.branch,
                            force: settings.force,
                            set_upstream: settings.set_upstream,
                            push_tags: settings.push_tags,
                        },
                        &git_command,
                    );

                    if result.is_ok() {
                        let _ = git::fetch(&path, &settings.remote, false, false, &git_command);
                    }

                    RepoViewMsg::PushComplete(result)
                });
            }

            RepoViewMsg::PushComplete(result) => {
                self.remote_op_in_progress = false;
                sender.output(RepoViewOutput::RemoteOpFinished).ok();

                match &result {
                    Ok(()) => root.add_toast(adw::Toast::new(&gettext("Push complete"))),
                    Err(msg) => root.add_toast(adw::Toast::new(msg)),
                }

                if result.is_ok() {
                    sender.input(RepoViewMsg::Refresh);
                }
            }

            _ => unreachable!("handle_push_message called with non-push message"),
        }
    }
}
