/* clone_progress_dialog.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 std::path::PathBuf;

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

use crate::git::CloneProgress;
use crate::ui_helpers;

pub struct CloneProgressDialogInit {
    pub parent_window: Option<gtk::Window>,
    pub destination: PathBuf,
}

#[derive(Debug)]
pub enum CloneProgressDialogMsg {
    UpdateProgress(CloneProgress),
    Finished,
    Failed(String),
}

#[derive(Debug)]
pub enum CloneProgressDialogOutput {
    Cancelled,
    Succeeded(PathBuf),
    Failed(String),
}

pub struct CloneProgressDialog {
    dialog: adw::AlertDialog,
    destination: PathBuf,
    progress_bar: gtk::ProgressBar,
}

#[relm4::component(pub)]
impl Component for CloneProgressDialog {
    type Init = CloneProgressDialogInit;
    type Input = CloneProgressDialogMsg;
    type Output = CloneProgressDialogOutput;
    type CommandOutput = ();

    view! {
        #[root]
        gtk::Box {
            set_orientation: gtk::Orientation::Vertical,

            #[name = "progress_bar"]
            gtk::ProgressBar {
                set_show_text: true,
                set_width_request: 350,
            },
        }
    }

    fn init(init: Self::Init, root: Self::Root, sender: ComponentSender<Self>) -> ComponentParts<Self> {
        let dialog = adw::AlertDialog::builder()
            .heading(gettext("Cloning Repository"))
            .build();

        let mut model = CloneProgressDialog {
            dialog,
            destination: init.destination,
            progress_bar: gtk::ProgressBar::new(),
        };

        let widgets = view_output!();

        model.progress_bar = widgets.progress_bar.clone();

        model.dialog.set_extra_child(Some(&root));

        model.dialog.add_response("cancel", &gettext("Cancel"));
        model
            .dialog
            .set_response_appearance("cancel", adw::ResponseAppearance::Destructive);
        model.dialog.set_default_response(Some("cancel"));
        model.dialog.set_close_response("cancel");

        model.dialog.connect_response(None, move |_dialog, response| {
            if response == "cancel" {
                sender.output(CloneProgressDialogOutput::Cancelled).ok();
            }
        });

        model.dialog.present(init.parent_window.as_ref());

        ComponentParts { model, widgets }
    }

    fn update(&mut self, msg: Self::Input, sender: ComponentSender<Self>, _root: &Self::Root) {
        match msg {
            CloneProgressDialogMsg::UpdateProgress(progress) => {
                if progress.total_objects > 0 {
                    let objects_done = progress.received_objects;
                    let objects_total = progress.total_objects;

                    if progress.received_objects < progress.total_objects {
                        let fraction = objects_done as f64 / objects_total as f64;

                        self.progress_bar.set_fraction(fraction);
                        self.progress_bar.set_text(Some(&format!(
                            "{}: {}/{} ({})",
                            gettext("Receiving objects"),
                            objects_done,
                            objects_total,
                            ui_helpers::format_bytes(progress.received_bytes),
                        )));
                    } else if progress.total_deltas > 0 {
                        let fraction = progress.indexed_deltas as f64 / progress.total_deltas as f64;

                        self.progress_bar.set_fraction(fraction);
                        self.progress_bar.set_text(Some(&format!(
                            "{}: {}/{}",
                            gettext("Indexing deltas"),
                            progress.indexed_deltas,
                            progress.total_deltas,
                        )));
                    }
                }
            }

            CloneProgressDialogMsg::Finished => {
                self.dialog.force_close();
                sender
                    .output(CloneProgressDialogOutput::Succeeded(self.destination.clone()))
                    .ok();
            }

            CloneProgressDialogMsg::Failed(msg) => {
                self.dialog.force_close();
                sender.output(CloneProgressDialogOutput::Failed(msg)).ok();
            }
        }
    }
}
