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

use crate::preferences;
use crate::window_content::{WindowContent, WindowContentInit, WindowContentMsg, WindowContentOutput};

pub struct AppWindowInit {
    pub folder_select_supported: bool,
    pub id: u64,
    pub initial_path: Option<PathBuf>,
}

pub struct AppWindow {
    id: u64,
    content: Controller<WindowContent>,
    search_action: gtk::gio::SimpleAction,
}

#[derive(Debug)]
pub enum AppWindowMsg {
    AddRepository,
    CloneRepository,
    OpenPath(PathBuf),
    ContentTitleChanged(String),
    ContentRepoPathChanged(Option<PathBuf>),
    FocusSearch,
    SearchEnabled(bool),
}

#[derive(Debug)]
pub enum AppWindowOutput {
    Closed(u64),
    RepoPathChanged { id: u64, path: Option<PathBuf> },
}

#[relm4::component(pub)]
impl Component for AppWindow {
    type Init = AppWindowInit;
    type Input = AppWindowMsg;
    type Output = AppWindowOutput;
    type CommandOutput = ();

    view! {
        adw::ApplicationWindow {
            set_title: Some("Gitte"),

            #[wrap(Some)]
            set_content = model.content.widget(),
        }
    }

    fn init(init: Self::Init, root: Self::Root, sender: ComponentSender<Self>) -> ComponentParts<Self> {
        let content = WindowContent::builder()
            .launch(WindowContentInit {
                folder_select_supported: init.folder_select_supported,
            })
            .forward(sender.input_sender(), |output| match output {
                WindowContentOutput::TitleChanged(title) => AppWindowMsg::ContentTitleChanged(title),
                WindowContentOutput::SearchEnabled(enabled) => AppWindowMsg::SearchEnabled(enabled),
                WindowContentOutput::RepoPathChanged(path) => AppWindowMsg::ContentRepoPathChanged(path),
            });

        let search_action = gtk::gio::SimpleAction::new("search", None);
        search_action.set_enabled(false);

        let model = AppWindow {
            id: init.id,
            content,
            search_action,
        };

        let widgets = view_output!();

        let root_clone = root.clone();
        let close_action = gtk::gio::SimpleAction::new("close", None);
        close_action.connect_activate(move |_, _| root_clone.close());
        root.add_action(&close_action);

        let s = sender.clone();
        let add_repo_action = gtk::gio::SimpleAction::new("add-repository", None);
        add_repo_action.connect_activate(move |_, _| s.input(AppWindowMsg::AddRepository));
        root.add_action(&add_repo_action);

        let s = sender.clone();
        let clone_repo_action = gtk::gio::SimpleAction::new("clone-repository", None);
        clone_repo_action.connect_activate(move |_, _| s.input(AppWindowMsg::CloneRepository));
        root.add_action(&clone_repo_action);

        let s = sender.clone();
        model
            .search_action
            .connect_activate(move |_, _| s.input(AppWindowMsg::FocusSearch));
        root.add_action(&model.search_action);

        let settings = preferences::app_settings();
        let width = settings.int("window-width");
        let height = settings.int("window-height");
        root.set_default_width(width);
        root.set_default_height(height);

        let output_sender = sender.output_sender().clone();
        let id = model.id;
        root.connect_close_request(move |win| {
            let settings = preferences::app_settings();
            let _ = settings.set_int("window-width", win.width());
            let _ = settings.set_int("window-height", win.height());
            let _ = output_sender.send(AppWindowOutput::Closed(id));
            glib::Propagation::Proceed
        });

        root.set_application(Some(&relm4::main_adw_application()));
        root.present();

        if let Some(path) = init.initial_path {
            sender.input(AppWindowMsg::OpenPath(path));
        }

        ComponentParts { model, widgets }
    }

    fn update(&mut self, msg: Self::Input, sender: ComponentSender<Self>, root: &Self::Root) {
        match msg {
            AppWindowMsg::AddRepository => self.content.emit(WindowContentMsg::AddRepository),
            AppWindowMsg::CloneRepository => self.content.emit(WindowContentMsg::CloneRepository),
            AppWindowMsg::ContentTitleChanged(title) => root.set_title(Some(&title)),
            AppWindowMsg::FocusSearch => self.content.emit(WindowContentMsg::FocusSearch),
            AppWindowMsg::SearchEnabled(enabled) => self.search_action.set_enabled(enabled),
            AppWindowMsg::OpenPath(path) => self.content.emit(WindowContentMsg::OpenPath(path)),

            AppWindowMsg::ContentRepoPathChanged(path) => {
                let _ = sender.output(AppWindowOutput::RepoPathChanged { id: self.id, path });
            }
        }
    }
}
