#!/usr/bin/python3

import importlib.util
import json
from pathlib import Path
import sys
import unittest


PROJECT_ROOT = Path(__file__).resolve().parents[1]
DATA_DIR = PROJECT_ROOT / "data"


class PageConfigTests(unittest.TestCase):
    def test_page_ids_are_known_and_unique(self):
        config = json.loads((DATA_DIR / "page_config.json").read_text(encoding="utf-8"))
        pages = config["main"]["pages"]
        known_pages = {
            "welcome",
            "drivers-pre-wifi",
            "network",
            "drivers-post-wifi",
            "installing-apps",
            "webbrowser",
            "apps",
            "samdemo",
            "donate",
            "explore",
        }

        self.assertEqual(len(pages), len(set(pages)))
        self.assertEqual(set(pages) - known_pages, set())


class AppCatalogTests(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        config = json.loads(
            (DATA_DIR / "example_apps_config.json").read_text(encoding="utf-8")
        )
        cls.categories = config["apps"]["categories"]

    def test_category_and_subcategory_ids_are_unambiguous(self):
        category_names = [category["name"] for category in self.categories]
        self.assertEqual(len(category_names), len(set(category_names)))

        all_subcategory_ids = []
        for category in self.categories:
            ids = [subcategory["id"] for subcategory in category["subcategories"]]
            self.assertEqual(len(ids), len(set(ids)), category["name"])
            all_subcategory_ids.extend(ids)
        self.assertEqual(len(all_subcategory_ids), len(set(all_subcategory_ids)))

    def test_every_app_references_a_subcategory_in_its_category(self):
        for category in self.categories:
            subcategory_ids = {
                subcategory["id"] for subcategory in category["subcategories"]
            }
            for app in category["apps"]:
                with self.subTest(category=category["name"], app=app["name"]):
                    self.assertIn(app["sub_category"], subcategory_ids)

    def test_app_names_are_unique_and_package_managers_are_supported(self):
        apps = [app for category in self.categories for app in category["apps"]]
        names = [app["name"] for app in apps]
        self.assertEqual(len(names), len(set(names)))
        for app in apps:
            with self.subTest(app=app["name"]):
                self.assertIn(app["package_manager"], {"flathub", "swai"})
                self.assertIsInstance(app["app_id"], str)
                self.assertTrue(app["description"].strip())


class FlatpakDesktopVerifierTests(unittest.TestCase):
    def test_firefox_desktop_id_matches_browser_pin_rule(self):
        verifier_path = PROJECT_ROOT / "scripts" / "verify_flatpak_desktops.py"
        spec = importlib.util.spec_from_file_location("verify_flatpak_desktops", verifier_path)
        verifier = importlib.util.module_from_spec(spec)
        sys.modules[spec.name] = verifier
        spec.loader.exec_module(verifier)

        self.assertEqual(
            verifier.FLATPAK_DESKTOP_MAP["org.mozilla.firefox"],
            "org.mozilla.firefox.desktop",
        )


class DriverManifestTests(unittest.TestCase):
    def test_shipped_manifests_have_required_fields_and_valid_phases(self):
        manifest_paths = sorted((DATA_DIR / "drivers").glob("*.json"))
        self.assertTrue(manifest_paths)

        ids = []
        for path in manifest_paths:
            manifest = json.loads(path.read_text(encoding="utf-8"))
            ids.append(manifest["id"])
            with self.subTest(manifest=path.name):
                self.assertIn(manifest["phase"], {"pre_wifi", "post_wifi"})
                self.assertIsInstance(manifest["requires_reboot"], bool)
                self.assertTrue(manifest["name"].strip())
                for key in ("check_script", "install_script", "success_script"):
                    self.assertIsInstance(manifest[key], (str, list))
                    if isinstance(manifest[key], list):
                        self.assertTrue(all(isinstance(line, str) for line in manifest[key]))
                    self.assertTrue(manifest[key])

        self.assertEqual(len(ids), len(set(ids)))


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