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

use super::{RepoView, RepoViewMsg, RepoViewOutput};
use crate::{git, preferences};

impl RepoView {
    pub(super) fn handle_fetch_message(
        &mut self,
        msg: RepoViewMsg,
        sender: &ComponentSender<RepoView>,
        root: &adw::ToastOverlay,
    ) {
        match msg {
            RepoViewMsg::FetchAll => {
                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 || {
                    RepoViewMsg::FetchAllComplete(git::fetch_all(&path, false, &git_command))
                });
            }

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

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

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

            RepoViewMsg::AutoFetchTick => {
                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 || {
                    RepoViewMsg::AutoFetchComplete(git::fetch_all(&path, false, &git_command))
                });
            }

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

                match &result {
                    Ok(()) => tracing::debug!("Auto-fetch completed successfully"),

                    Err(msg) if msg == "No remotes configured" => {
                        tracing::debug!("Auto-fetch: no remotes configured, stopping timer");
                        self.stop_auto_fetch_timer();
                    }

                    Err(msg) => tracing::warn!("Auto-fetch failed: {msg}"),
                }

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

            RepoViewMsg::AutoFetchSettingsChanged => {
                self.restart_auto_fetch_timer(sender);
            }

            _ => unreachable!("handle_fetch_message called with non-fetch message"),
        }
    }

    pub(super) fn stop_auto_fetch_timer(&mut self) {
        if let Some(id) = self.auto_fetch_source_id.take() {
            glib::SourceId::remove(id);
        }
    }

    pub(super) fn restart_auto_fetch_timer(&mut self, sender: &ComponentSender<Self>) {
        self.stop_auto_fetch_timer();

        let mode = self.settings.string("auto-fetch-mode");
        let (enabled, interval) = match mode.as_str() {
            "enabled" => {
                let interval = self.settings.int("auto-fetch-interval") as u32;
                (true, interval)
            }

            "disabled" => (false, 0),

            _ => {
                let enabled = self.global_settings.boolean("auto-fetch-enabled");
                let interval = self.global_settings.int("auto-fetch-interval") as u32;

                (enabled, interval)
            }
        };

        if enabled {
            let s = sender.input_sender().clone();
            self.auto_fetch_source_id = Some(glib::timeout_add_seconds_local(interval, move || {
                s.emit(RepoViewMsg::AutoFetchTick);
                glib::ControlFlow::Continue
            }));
        }
    }
}
