#!/usr/bin/python3
"""Regression tests for the deferred browser setup flow.

The browser selection page only records selections. Browser installs and dock
favorites must happen when the user completes the subsequent Apps page.
"""

from pathlib import Path
import re
import unittest


PROJECT_ROOT = Path(__file__).resolve().parents[1]


def method_body(source: str, method_name: str) -> str:
    match = re.search(rf"private void {re.escape(method_name)}\(\)\s*\{{", source)
    if match is None:
        raise AssertionError(f"Could not find {method_name}()")

    depth = 1
    index = match.end()
    body_start = index
    while index < len(source) and depth:
        if source[index] == "{":
            depth += 1
        elif source[index] == "}":
            depth -= 1
        index += 1

    if depth:
        raise AssertionError(f"Unterminated {method_name}()")
    return source[body_start : index - 1]


class BrowserSetupFlowTests(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        cls.browser_page = (PROJECT_ROOT / "src/pages/webbrowser.vala").read_text(
            encoding="utf-8"
        )
        cls.apps_page = (PROJECT_ROOT / "src/pages/apps.vala").read_text(
            encoding="utf-8"
        )
        cls.app_pins = (PROJECT_ROOT / "src/app_pins.vala").read_text(
            encoding="utf-8"
        )

    def test_browser_page_defers_browser_install_and_pinning_until_apps_page(self):
        browser_next = method_body(self.browser_page, "next_button_clicked")
        self.assertNotIn("install_app(", browser_next)
        self.assertNotIn("pin_checked_browsers", browser_next)
        self.assertIn("context.window.push_next_page();", browser_next)

        apps_next = method_body(self.apps_page, "next_button_clicked")
        self.assertIn("pin_checked_browsers_in_categories(this.categories);", apps_next)
        self.assertIn("install_app(app, \"INSTALL\");", apps_next)

    def test_apps_completion_syncs_browser_favorites_for_selected_or_fallback_web(self):
        apps_next = method_body(self.apps_page, "next_button_clicked")
        self.assertIn("context.window.ensure_browser_pinned();", apps_next)
        self.assertLess(
            apps_next.index("install_app(app, \"INSTALL\");"),
            apps_next.index("context.window.ensure_browser_pinned();"),
        )
    def test_browser_sync_pins_every_installed_browser(self):
        ensure_browser_pinned = re.search(
            r"public void ensure_browser_pinned\(\)\s*\{(?P<body>.*?)\n        \}",
            (PROJECT_ROOT / "src/window.vala").read_text(encoding="utf-8"),
            re.DOTALL,
        )
        self.assertIsNotNone(ensure_browser_pinned)
        self.assertIn("sync_browser_favorites();", ensure_browser_pinned.group("body"))
        self.assertIn("public void sync_browser_favorites()", self.app_pins)
        sync_start = self.app_pins.index("public void sync_browser_favorites()")
        sync_end = self.app_pins.index("public void configure_gnome_app_folders()", sync_start)
        sync_body = self.app_pins[sync_start:sync_end]
        self.assertIn("foreach (var desktop_file in BROWSER_DESKTOPS)", sync_body)
        self.assertIn("prepend_shell_favorite(desktop_file);", sync_body)
        self.assertNotIn("preferred_browser", sync_body)
        self.assertNotIn("remove_shell_favorite", sync_body)
        self.assertNotIn("org.gnome.Epiphany.desktop", self.app_pins)

    def test_all_selected_browsers_are_pinned(self):
        pin_start = self.app_pins.index("public void pin_checked_browsers(")
        pin_end = self.app_pins.index("public void pin_checked_browsers_in_categories(", pin_start)
        pin_body = self.app_pins[pin_start:pin_end]
        self.assertIn("foreach (var app in apps)", pin_body)
        self.assertIn("pin_browser_if_checked(app);", pin_body)
        self.assertNotIn("return;", pin_body)

    def test_browser_pins_are_first_in_favorites(self):
        prepend_start = self.app_pins.index("private static void prepend_shell_favorite(")
        prepend_end = self.app_pins.index("private static bool shell_favorites_contains(", prepend_start)
        prepend_body = self.app_pins[prepend_start:prepend_end]
        self.assertIn("string[] updated = { desktop_file };", prepend_body)

        helper = (PROJECT_ROOT / "scripts/quick-setup-browser-pin-helper").read_text(
            encoding="utf-8"
        )
        self.assertIn("favorites.insert(0, desktop_file)", helper)


if __name__ == "__main__":
    unittest.main()
