namespace ProtonPlus.Widgets.Loading {
    public class Box : Gtk.Box {
        public signal void loaded (Gee.LinkedList<Models.Launcher> launchers);

        public bool loading { get; set; }

        Adw.StatusPage status_page { get; set; }
        Adw.Spinner spinner { get; set; }
        Gtk.FlowBox bug_box { get; set; }
        Gtk.Box welcome_box { get; set; }
        Gtk.Button retry_button { get; set; }
        Gtk.Button report_button { get; set; }
        uint slow_warning_timeout_id = 0;

        public Box () {
            Object (orientation: Gtk.Orientation.VERTICAL, spacing: 0);

            spinner = new Adw.Spinner ();
            spinner.set_size_request (32, 32);
            spinner.set_halign (Gtk.Align.CENTER);
            spinner.set_valign (Gtk.Align.CENTER);

            bind_property ("loading", spinner, "visible", GLib.BindingFlags.DEFAULT);

            bug_box = create_bug_box ();

            welcome_box = create_welcome_box ();

            var content_box = new Gtk.Box (Gtk.Orientation.VERTICAL, 30);
            content_box.set_halign (Gtk.Align.CENTER);
            content_box.append (spinner);
            content_box.append (bug_box);
            content_box.append (welcome_box);

            status_page = new Adw.StatusPage ();
            status_page.set_vexpand (true);
            status_page.set_hexpand (true);
            status_page.set_child (content_box);

            append (status_page);
        }

        public async void load () {
            if (loading)
                return;

            loading = true;
            status_page.add_css_class ("loading-status-page");

            bug_box.visible = false;
            welcome_box.visible = false;

            status_page.set_icon_name ("com.vysp3r.ProtonPlus");
            status_page.set_title (_ ("Loading"));
            status_page.set_description (_ ("Please wait while we're loading your launchers."));

            if (slow_warning_timeout_id != 0)
                Source.remove (slow_warning_timeout_id);
            slow_warning_timeout_id = Timeout.add_seconds (15, () => {
                slow_warning_timeout_id = 0;
                if (loading) {
                    status_page.set_description (_ ("Taking longer than normal?"));
                    retry_button.visible = false;
                    report_button.visible = true;
                    bug_box.visible = true;
                }

                return false;
            });

            Gee.LinkedList<Models.Launcher> launchers;

            var success = yield Models.Launcher.get_all (out launchers);

            loading = false;
            status_page.remove_css_class ("loading-status-page");
            if (slow_warning_timeout_id != 0) {
                Source.remove (slow_warning_timeout_id);
                slow_warning_timeout_id = 0;
            }

            if (!success) {
                status_page.set_icon_name ("bug-symbolic");
                status_page.set_title (_ ("An unexpected error occurred"));
                status_page.set_description (_ ("We encountered a problem while loading your application.\nPlease try again or report the problem."));
                retry_button.visible = true;
                report_button.visible = true;
                bug_box.visible = true;
                return;
            }

            bug_box.visible = false;

            if (launchers.size > 0) {
                loaded (launchers);
            } else {
                status_page.set_title (_ ("Welcome to %s").printf (Config.APP_NAME));
                status_page.set_description (null);
                welcome_box.visible = true;
            }
        }

        Gtk.Button create_icon_button (string label, string icon_name, bool suggested = false) {
            var button_content = new Adw.ButtonContent () {
                icon_name = icon_name,
                label = label,
            };

            return create_button (button_content, suggested);
        }

        Gtk.Button create_image_button (string label, string filename, bool suggested = false) {
            var button_image = new Gtk.Image.from_resource ("%s/%s".printf (Config.RESOURCE_BASE, filename));

            var button_label = new Gtk.Label (label);

            var button_box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 12);
            button_box.append (button_image);
            button_box.append (button_label);

            return create_button (button_box, suggested);
        }

        Gtk.Button create_button (Gtk.Widget child, bool suggested) {
            var button = new Gtk.Button ();
            button.set_child (child);
            button.set_halign (Gtk.Align.CENTER);
            button.add_css_class ("pill");
            if (suggested)
                button.add_css_class ("suggested-action");

            return button;
        }

        Gtk.FlowBox create_bug_box () {
            retry_button = create_icon_button (_ ("Retry loading"), "view-refresh-symbolic", true);
            retry_button.clicked.connect (() => {
                load.begin ();
            });

            report_button = create_icon_button (_ ("Report issue"), "github-symbolic");
            report_button.clicked.connect (() => {
                activate_action ("app.report", null);
            });

            var bug_box = new Gtk.FlowBox () {
                column_spacing = 12,
                row_spacing = 12,
                max_children_per_line = 2,
                min_children_per_line = 1,
                selection_mode = Gtk.SelectionMode.NONE,
                halign = Gtk.Align.CENTER
            };
            bug_box.append (retry_button);
            bug_box.append (report_button);

            return bug_box;
        }

        Gtk.Box create_welcome_box () {
            var first_label = create_wrapping_label (_ ("You need a game launcher to use ProtonPlus."));

            var second_label = create_wrapping_label (_ ("Install one of these to get started:"));

            var steam_button = create_image_button ("Steam", "steam.svg");
            steam_button.clicked.connect (() => {
                Utils.System.open_uri ("https://store.steampowered.com/about/");
            });

            var faugus_button = create_image_button ("Faugus Launcher", "faugus-launcher.svg");
            faugus_button.clicked.connect (() => {
                Utils.System.open_uri ("https://github.com/Faugus/faugus-launcher");
            });

            var lutris_button = create_image_button ("Lutris", "lutris.svg");
            lutris_button.clicked.connect (() => {
                Utils.System.open_uri ("https://lutris.net/");
            });

            var hgl_button = create_image_button ("Heroic Games Launcher", "hgl.svg");
            hgl_button.clicked.connect (() => {
                Utils.System.open_uri ("https://heroicgameslauncher.com/");
            });

            var bottles_button = create_image_button ("Bottles", "bottles.svg");
            bottles_button.clicked.connect (() => {
                Utils.System.open_uri ("https://usebottles.com/");
            });

            var winezgui_button = create_image_button ("WineZGUI", "winezgui.svg");
            winezgui_button.clicked.connect (() => {
                Utils.System.open_uri ("https://github.com/fastrizwaan/WineZGUI");
            });

            var launchers_box = new Gtk.FlowBox ();
            launchers_box.set_selection_mode (Gtk.SelectionMode.NONE);
            launchers_box.append (steam_button);
            launchers_box.append (faugus_button);
            launchers_box.append (lutris_button);
            launchers_box.append (hgl_button);
            launchers_box.append (bottles_button);
            launchers_box.append (winezgui_button);

            var third_label = create_wrapping_label (_ ("Important: Run the launcher once to initialize it properly."));

            var check_button = create_icon_button (_ ("Check again"), "view-refresh-symbolic", true);
            check_button.clicked.connect (() => {
                load.begin ();
            });

            var welcome_box = new Gtk.Box (Gtk.Orientation.VERTICAL, 12);
            welcome_box.append (first_label);
            welcome_box.append (second_label);
            welcome_box.append (launchers_box);
            welcome_box.append (third_label);
            welcome_box.append (check_button);

            return welcome_box;
        }

        Gtk.Label create_wrapping_label (string text) {
            return new Gtk.Label (text) {
                wrap = true,
                justify = Gtk.Justification.CENTER,
                max_width_chars = 48
            };
        }

        public override void dispose () {
            if (slow_warning_timeout_id != 0) {
                Source.remove (slow_warning_timeout_id);
                slow_warning_timeout_id = 0;
            }
            base.dispose ();
        }
    }
}
