namespace QuickSetup {
    private const string PATREON_URL = "https://www.patreon.com/cw/stillHQ";
    private const string PATREON_DATA_URL = "https://gitlab.com/stillhq/stillOS/quick-setup/-/raw/patreon/patreon.yaml";
    private const double DEFAULT_DONATION_GOAL_USD = 5000.0;
    private const int64 DONATION_REMINDER_DELAY_SECONDS = 30 * 24 * 60 * 60;
    private const string FALLBACK_PATREON_YAML = """
current_amount: 0
currency: USD
goal:
  amount: 5000
  label: Promised feature update every 2 months
individuals: []
""";

    public class DonationGoal : Object {
        public double amount { get; set; default = 0.0; }
        public string label { get; set; default = ""; }
    }

    public class DonationIndividual : Object {
        public string name { get; set; default = ""; }
        public string note { get; set; default = ""; }
    }

    public class DonationData : Object {
        public double current_amount { get; set; default = 0.0; }
        public string currency { get; set; default = "USD"; }
        public DonationGoal? goal { get; set; }
        public List<DonationIndividual> individuals;

        public DonationData() {
            this.individuals = new List<DonationIndividual>();
        }
    }

    public class DonatePage : QsPage {
        private Gtk.ProgressBar progress_bar;
        private Gtk.Label current_amount_label;
        private Gtk.Label goal_amount_label;
        private Gtk.Label details_label;
        private Gtk.Box goals_box;
        private Adw.PreferencesGroup individuals_group;

        public override string page_id { get { return "donate"; } }
        public override bool can_go_back_to { get { return true; } }
        public override bool needs_network { get { return true; } }

        public DonatePage(PageContext context) {
            base(context, "Support stillOS");

            this.setup_ui();
            this.load_patreon_progress.begin();
        }

        private void setup_ui() {
            var clamp = new Adw.Clamp();
            clamp.maximum_size = 760;
            clamp.tightening_threshold = 480;
            clamp.vexpand = true;
            clamp.valign = Gtk.Align.CENTER;

            var content_box = new Gtk.Box(Gtk.Orientation.VERTICAL, 20);
            content_box.margin_top = 32;
            content_box.margin_bottom = 32;
            content_box.margin_start = 24;
            content_box.margin_end = 24;
            content_box.valign = Gtk.Align.CENTER;

            var title_label = new Gtk.Label(tr("Help Make stillOS Possible"));
            title_label.wrap = true;
            title_label.justify = Gtk.Justification.CENTER;
            title_label.halign = Gtk.Align.CENTER;
            title_label.add_css_class("title-1");

            var description_label = new Gtk.Label(tr("stillOS is primarily developed by a college student working another job on top of stillOS. Help make stillOS his full time work."));
            description_label.wrap = true;
            description_label.justify = Gtk.Justification.CENTER;
            description_label.halign = Gtk.Align.CENTER;
            description_label.add_css_class("body");

            var progress_row = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 12);
            progress_row.valign = Gtk.Align.CENTER;

            this.current_amount_label = new Gtk.Label("$0");
            this.current_amount_label.xalign = 0.0f;
            this.current_amount_label.add_css_class("heading");
            progress_row.append(this.current_amount_label);

            this.progress_bar = new Gtk.ProgressBar();
            this.progress_bar.hexpand = true;
            this.progress_bar.fraction = 0.0;
            this.progress_bar.show_text = false;
            this.progress_bar.valign = Gtk.Align.CENTER;
            progress_row.append(this.progress_bar);

            this.goal_amount_label = new Gtk.Label("$5,000");
            this.goal_amount_label.xalign = 1.0f;
            this.goal_amount_label.add_css_class("heading");
            progress_row.append(this.goal_amount_label);

            this.details_label = new Gtk.Label(tr("Loading goal and supporter shoutouts..."));
            this.details_label.wrap = true;
            this.details_label.justify = Gtk.Justification.CENTER;
            this.details_label.halign = Gtk.Align.CENTER;
            this.details_label.add_css_class("dim-label");

            var individuals_heading = new Gtk.Label(tr("Thank You to these Big Time Supporters:"));
            individuals_heading.xalign = 0.0f;
            individuals_heading.halign = Gtk.Align.FILL;
            individuals_heading.add_css_class("heading");

            this.individuals_group = new Adw.PreferencesGroup();

            var individuals_scroll = new Gtk.ScrolledWindow();
            individuals_scroll.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
            individuals_scroll.min_content_height = 112;
            individuals_scroll.max_content_height = 180;
            individuals_scroll.propagate_natural_height = true;
            individuals_scroll.set_child(this.individuals_group);

            var no_thanks_button = new Gtk.Button.with_label(tr("No Thanks"));
            no_thanks_button.add_css_class("pill");
            no_thanks_button.clicked.connect(() => {
                this.context.window.push_next_page();
            });

            var remind_button = new Gtk.Button.with_label(tr("Remind Me in 30 Days"));
            remind_button.add_css_class("pill");
            remind_button.clicked.connect(() => {
                this.schedule_donation_reminder();
                this.context.window.push_next_page();
            });

            var support_button = new Gtk.Button.with_label(tr("Support on Patreon"));
            support_button.add_css_class("suggested-action");
            support_button.add_css_class("pill");
            support_button.clicked.connect(() => {
                this.support_on_patreon();
            });

            var button_bar = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 12);
            button_bar.halign = Gtk.Align.CENTER;
            button_bar.homogeneous = true;
            button_bar.margin_top = 24;
            button_bar.append(no_thanks_button);
            button_bar.append(remind_button);
            button_bar.append(support_button);

            content_box.append(title_label);
            content_box.append(description_label);
            content_box.append(progress_row);
            content_box.append(this.details_label);
            content_box.append(individuals_heading);
            content_box.append(individuals_scroll);
            content_box.append(button_bar);

            clamp.set_child(content_box);
            this.add_content(clamp);
        }

        private void support_on_patreon() {
            this.open_patreon_dialog();
        }

        private void open_patreon_dialog() {
            var dialog = new Adw.Dialog();
            dialog.set_title(tr("Support stillOS on Patreon"));
            dialog.set_content_width(1100);
            dialog.set_content_height(800);
            dialog.set_can_close(true);

            var content_box = new Gtk.Box(Gtk.Orientation.VERTICAL, 0);

            var toolbar_view = new Adw.ToolbarView();
            toolbar_view.vexpand = true;

            var header_bar = new Adw.HeaderBar();
            header_bar.set_title_widget(new Adw.WindowTitle(tr("Support stillOS on Patreon"), ""));
            var web_view = new WebKit.WebView();
            var back_button = new Gtk.Button();
            back_button.set_icon_name("go-previous-symbolic");
            back_button.add_css_class("flat");
            back_button.tooltip_text = tr("Back");
            back_button.sensitive = false;
            back_button.clicked.connect(() => {
                if (web_view.can_go_back()) {
                    web_view.go_back();
                }
            });
            header_bar.pack_start(back_button);
            toolbar_view.add_top_bar(header_bar);

            web_view.load_changed.connect(() => {
                back_button.sensitive = web_view.can_go_back();
            });
            web_view.load_uri(PATREON_URL);
            toolbar_view.set_content(web_view);

            var action_box = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 12);
            action_box.margin_top = 18;
            action_box.margin_bottom = 18;
            action_box.margin_start = 18;
            action_box.margin_end = 18;
            action_box.halign = Gtk.Align.END;

            var remind_button = new Gtk.Button.with_label(tr("Remind Me Later"));
            remind_button.add_css_class("pill");
            remind_button.clicked.connect(() => {
                this.schedule_donation_reminder();
                dialog.close();
                this.context.window.push_next_page();
            });

            var done_button = new Gtk.Button.with_label(tr("Done"));
            done_button.add_css_class("pill");
            done_button.add_css_class("suggested-action");
            done_button.clicked.connect(() => {
                this.clear_donation_reminder();
                dialog.close();
                this.context.window.push_next_page();
            });

            action_box.append(remind_button);
            action_box.append(done_button);

            content_box.append(toolbar_view);
            content_box.append(action_box);

            dialog.set_child(content_box);
            dialog.present(this.context.window);
        }

        private async void load_patreon_progress() {
            DonationData donation_data = this.parse_donation_yaml(FALLBACK_PATREON_YAML);
            var session = new Soup.Session();
            var message = new Soup.Message("GET", PATREON_DATA_URL);

            try {
                var bytes = yield session.send_and_read_async(message, GLib.Priority.DEFAULT, null);
                if (message.status_code == 200) {
                    string yaml_body = (string) bytes.get_data();
                    donation_data = this.parse_donation_yaml(yaml_body);
                }
            } catch (Error e) {
                warning("Failed to load Patreon YAML: %s", e.message);
            }

            this.update_donation_data(donation_data);
        }

        private DonationData parse_donation_yaml(string yaml_string) {
            var donation_data = new DonationData();
            string section = "";
            DonationGoal? current_goal = null;
            DonationIndividual? current_individual = null;

            foreach (unowned string raw_line in yaml_string.split("\n")) {
                string line = raw_line.strip();
                if (line == "" || line.has_prefix("#")) {
                    continue;
                }

                if (line == "goal:" || line == "goal: {}") {
                    section = "goal";
                    current_goal = null;
                    continue;
                }

                // Backward-compatible: if older YAML still uses goals, keep only the first one.
                if (line == "goals:" || line == "goals: []") {
                    section = "goals";
                    current_goal = null;
                    continue;
                }

                if (line == "individuals:" || line == "individuals: []") {
                    section = "individuals";
                    current_individual = null;
                    continue;
                }

                if (section == "goals" && line.has_prefix("- ")) {
                    if (donation_data.goal != null) {
                        current_goal = null;
                        continue;
                    }

                    current_goal = new DonationGoal();
                    donation_data.goal = current_goal;
                    this.apply_goal_yaml_line(current_goal, line.substring(2).strip());
                    continue;
                }

                if (section == "goal") {
                    if (donation_data.goal == null) {
                        donation_data.goal = new DonationGoal();
                    }
                    current_goal = donation_data.goal;
                }

                if (section == "goal" && current_goal != null) {
                    this.apply_goal_yaml_line(current_goal, line);
                    continue;
                }

                if (section == "individuals" && line.has_prefix("- ")) {
                    current_individual = new DonationIndividual();
                    donation_data.individuals.append(current_individual);

                    string entry = line.substring(2).strip();
                    if (entry.contains(":")) {
                        this.apply_individual_yaml_line(current_individual, entry);
                    } else {
                        current_individual.name = this.unquote_yaml_value(entry);
                    }
                    continue;
                }

                if (section == "goals" && current_goal != null) {
                    this.apply_goal_yaml_line(current_goal, line);
                    continue;
                }

                if (section == "individuals" && current_individual != null) {
                    this.apply_individual_yaml_line(current_individual, line);
                    continue;
                }

                this.apply_donation_yaml_line(donation_data, line);
            }

            if (donation_data.goal == null) {
                donation_data = this.parse_donation_yaml(FALLBACK_PATREON_YAML);
            }

            return donation_data;
        }

        private void apply_donation_yaml_line(DonationData donation_data, string line) {
            string key;
            string value;
            if (!this.split_yaml_pair(line, out key, out value)) {
                return;
            }

            switch (key) {
                case "current_amount":
                case "amount":
                    donation_data.current_amount = this.parse_amount(value);
                    break;
                case "currency":
                    donation_data.currency = this.unquote_yaml_value(value);
                    break;
                default:
                    break;
            }
        }

        private void apply_goal_yaml_line(DonationGoal goal, string line) {
            string key;
            string value;
            if (!this.split_yaml_pair(line, out key, out value)) {
                return;
            }

            switch (key) {
                case "amount":
                    goal.amount = this.parse_amount(value);
                    break;
                case "label":
                case "title":
                case "description":
                    goal.label = this.unquote_yaml_value(value);
                    break;
                default:
                    break;
            }
        }

        private void apply_individual_yaml_line(DonationIndividual individual, string line) {
            string key;
            string value;
            if (!this.split_yaml_pair(line, out key, out value)) {
                return;
            }

            switch (key) {
                case "name":
                    individual.name = this.unquote_yaml_value(value);
                    break;
                case "note":
                case "tier":
                    individual.note = this.unquote_yaml_value(value);
                    break;
                default:
                    break;
            }
        }

        private bool split_yaml_pair(string line, out string key, out string value) {
            key = "";
            value = "";

            int separator_index = line.index_of(":");
            if (separator_index < 0) {
                return false;
            }

            key = line.substring(0, separator_index).strip();
            value = line.substring(separator_index + 1).strip();
            return true;
        }

        private string unquote_yaml_value(string value) {
            string stripped = value.strip();
            if (stripped.length >= 2) {
                if ((stripped.has_prefix("\"") && stripped.has_suffix("\"")) ||
                    (stripped.has_prefix("'") && stripped.has_suffix("'"))) {
                    return stripped.substring(1, stripped.length - 2);
                }
            }

            return stripped;
        }

        private double parse_amount(string value) {
            string cleaned = this.unquote_yaml_value(value).replace("$", "").replace(",", "");
            if (cleaned == "") {
                return 0.0;
            }

            try {
                return double.parse(cleaned);
            } catch (Error e) {
                return 0.0;
            }
        }

        private double get_display_goal_amount(DonationData donation_data) {
            if (donation_data.goal != null && donation_data.goal.amount > 0.0) {
                return donation_data.goal.amount;
            }

            return DEFAULT_DONATION_GOAL_USD;
        }

        private void update_donation_data(DonationData donation_data) {
            double goal_amount = this.get_display_goal_amount(donation_data);
            double fraction = donation_data.current_amount / goal_amount;
            if (fraction < 0.0) {
                fraction = 0.0;
            }
            if (fraction > 1.0) {
                fraction = 1.0;
            }

            this.progress_bar.fraction = fraction;
            this.current_amount_label.set_label(this.format_currency(donation_data.current_amount, donation_data.currency));
            this.goal_amount_label.set_label(this.format_currency(goal_amount, donation_data.currency));
            this.details_label.set_label("");

            this.populate_individuals(donation_data);
        }

        private void populate_individuals(DonationData donation_data) {
            this.clear_preferences_group(this.individuals_group);

            if (donation_data.individuals.length() == 0) {
                var empty_row = new Adw.ActionRow();
                empty_row.title = tr("No Big Time Supporters Yet");
                empty_row.subtitle = tr("$25 a month supporters will be listed here.");
                empty_row.activatable = false;
                this.individuals_group.add(empty_row);
                return;
            }

            foreach (var individual in donation_data.individuals) {
                var individual_row = new Adw.ActionRow();
                individual_row.title = individual.name;
                individual_row.activatable = false;
                if (individual.note != "") {
                    individual_row.subtitle = individual.note;
                }
                this.individuals_group.add(individual_row);
            }
        }

        private void clear_preferences_group(Adw.PreferencesGroup group) {
            var child = group.get_first_child();
            while (child != null) {
                var next_child = child.get_next_sibling();
                group.remove(child);
                child = next_child;
            }
        }

        private string format_currency(double amount, string currency) {
            if (currency == "USD") {
                return "$%.0f".printf(amount);
            }

            return "%.0f %s".printf(amount, currency);
        }

        private void schedule_donation_reminder() {
            try {
                var settings = new GLib.Settings("io.stillhq.quicksetup");
                int64 now = GLib.get_real_time() / 1000000;
                int64 remind_at = now + DONATION_REMINDER_DELAY_SECONDS;

                settings.set_boolean("donation-reminder-enabled", true);
                settings.set_int64("donation-reminder-unix-time", remind_at);
            } catch (Error e) {
                warning("Failed to schedule donation reminder: %s", e.message);
            }
        }

        private void clear_donation_reminder() {
            try {
                var settings = new GLib.Settings("io.stillhq.quicksetup");
                settings.set_boolean("donation-reminder-enabled", false);
                settings.set_int64("donation-reminder-unix-time", 0);
            } catch (Error e) {
                warning("Failed to clear donation reminder: %s", e.message);
            }
        }
    }
}
