public static string get_default_web_browser_json() {
    return QuickSetup.DEFAULT_WEB_BROWSER_JSON;
}

public static QuickSetup.CategoryData parse_category_from_json_string(string json_string) {
    try {
        var parser = new Json.Parser();
        parser.load_from_data(json_string);
        var category_obj = parser.get_root().get_object();
        
        // Parse category from JSON object
        var category = new QuickSetup.CategoryData();
        category.name = QuickSetup.tr(category_obj.get_string_member("name"));
        category.description = QuickSetup.tr(category_obj.get_string_member("description"));
        category.icon_name = category_obj.get_string_member("icon_name");
        category.sub_categories = new List<QuickSetup.SubCategoryData>();
        category.apps = new List<QuickSetup.AppData>();
        category.selected_apps = new List<QuickSetup.AppData>();

        // Parse subcategories
        if (category_obj.has_member("subcategories")) {
            var subcategories_array = category_obj.get_array_member("subcategories");
            var sub_length = subcategories_array.get_length();
            
            for (int i = 0; i < sub_length; i++) {
                var sub_obj = subcategories_array.get_object_element(i);
                var sub_category = new QuickSetup.SubCategoryData();
                sub_category.id = sub_obj.get_string_member("id");
                sub_category.name = QuickSetup.tr(sub_obj.get_string_member("name"));
                sub_category.description = QuickSetup.tr(sub_obj.get_string_member("description"));
                category.sub_categories.append(sub_category);
            }
        }

        // Parse apps
        if (category_obj.has_member("apps")) {
            var apps_array = category_obj.get_array_member("apps");
            var apps_length = apps_array.get_length();
            
            for (int i = 0; i < apps_length; i++) {
                var app_obj = apps_array.get_object_element(i);
                var app = new QuickSetup.AppData();
                app.name = QuickSetup.tr(app_obj.get_string_member("name"));
                app.app_id = app_obj.get_string_member("app_id");
                app.description = QuickSetup.tr(app_obj.get_string_member("description"));
                app.styleclass = app_obj.has_member("styleclass") ? app_obj.get_string_member("styleclass") : "";
                app.sub_category = app_obj.has_member("sub_category") ? app_obj.get_string_member("sub_category") : null;
                app.package_manager = app_obj.has_member("package_manager") ? app_obj.get_string_member("package_manager") : "flathub";
                app.checked = false;
                category.apps.append(app);
            }
        }

        return category;
    } catch (Error e) {
        warning("Failed to parse category JSON: %s", e.message);
        // Return empty category as fallback
        var category = new QuickSetup.CategoryData();
        category.name = QuickSetup.tr("Browser Selection");
        category.description = QuickSetup.tr("Error loading browser list");
        category.icon_name = "web-browser-symbolic";
        category.sub_categories = new List<QuickSetup.SubCategoryData>();
        category.apps = new List<QuickSetup.AppData>();
        category.selected_apps = new List<QuickSetup.AppData>();
        return category;
    }
}

public static QuickSetup.CategoryData load_web_browser_category_from_config(QuickSetup.PageContext context) {
    var object = context.config.get_page_object("webbrowser");

    // If no config exists, parse default JSON
    if (object == null || !object.has_member("category")) {
        return parse_category_from_json_string(get_default_web_browser_json());
    }

    var category_obj = object.get_object_member("category");
    if (category_obj == null) {
        return parse_category_from_json_string(get_default_web_browser_json());
    }

    // Convert JsonObject back to JSON string and parse using the common function
    var generator = new Json.Generator();
    var node = new Json.Node(Json.NodeType.OBJECT);
    node.set_object(category_obj);
    generator.set_root(node);
    string json_string = generator.to_data(null);
    
    return parse_category_from_json_string(json_string);
}

public static QuickSetup.CategoryData get_shared_web_browser_category(QuickSetup.PageContext context) {
    if (context.window.shared_web_browser_category != null) {
        return context.window.shared_web_browser_category;
    }

    var category = load_web_browser_category_from_config(context);
    category.allow_success_styleclass = true;
    context.window.shared_web_browser_category = category;
    return category;
}

namespace QuickSetup {
    public class WebBrowserPage : CategoryPage {
        public override string page_id { get { return "webbrowser"; } }
        public override bool can_go_back_to { get { return false; } }
        public override bool needs_network { get { return true; } }

        public WebBrowserPage(PageContext context) {
            var category = get_shared_web_browser_category(context);

            base(context, category);

            this.setup_additional_ui();
        }

        private void setup_additional_ui() {
            var action_group = new Adw.PreferencesGroup();
            this.selection_page.add(action_group);

            var button_bar = this.create_trailing_button_bar();
            var button = this.create_page_button("Next", true);
            button.clicked.connect(() => {
                this.next_button_clicked();
            });
            button_bar.append(button);
            action_group.add(button_bar);
        }

        private void next_button_clicked() {
            // Browser selections are shared with AppsPage. Defer installation and
            // dock pinning until the user confirms the complete app selection.
            context.window.push_next_page();
        }
    }
}
