# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

from marionette_driver.by import By
from marionette_harness import MarionetteTestCase
from mozfile import json

vertical_parent_id = "vertical-tabs"
horizontal_parent_id = "TabsToolbar-customization-target"
snapshot_pref = "browser.uiCustomization.horizontalTabstrip"
customization_pref = "browser.uiCustomization.state"


class TestInitializeVerticalTabs(MarionetteTestCase):
    def setUp(self):
        super().setUp()
        self.marionette.set_context("chrome")

    def tearDown(self):
        try:
            # Make sure subsequent tests get a clean profile
            self.marionette.restart(in_app=False, clean=True)
        finally:
            super().tearDown()

    def restart_with_prefs(self, prefs):
        # We need to quit the browser and restart with the prefs already set
        # in order to examine the startup behavior
        for name, value in prefs.items():
            if value is None:
                self.marionette.clear_pref(name)
            else:
                self.marionette.set_pref(name, value)
        self.marionette.restart(clean=False, in_app=True)
        self.marionette.set_context("chrome")

    def get_area_widgets(self, area):
        return self.marionette.execute_script(
            f"return CustomizableUI.getWidgetIdsInArea(CustomizableUI.{area})"
        )

    def check_tabs_toolbar_visibilities(self, orientation="vertical"):
        self.marionette.set_context("chrome")
        h_tabstoolbar = self.marionette.find_element(By.ID, "TabsToolbar")
        v_tabstoolbar = self.marionette.find_element(By.ID, "vertical-tabs")

        h_collapsed = self.marionette.execute_script(
            "return document.getElementById(CustomizableUI.AREA_TABSTRIP).getAttribute('collapsed')"
        )
        v_collapsed = self.marionette.execute_script(
            "return document.getElementById(CustomizableUI.AREA_VERTICAL_TABSTRIP).getAttribute('collapsed')"
        )

        if orientation == "vertical":
            self.assertEqual(
                h_collapsed,
                "",
                "Horizontal tab strip has expected collapsed attribute value",
            )
            self.assertEqual(
                v_collapsed,
                None,
                "Vertical tab strip has expected collapsed attribute value",
            )

            self.assertFalse(
                h_tabstoolbar.is_displayed(), "Horizontal tab strip is not displayed"
            )

            self.assertTrue(
                v_tabstoolbar.is_displayed(), "Vertical tab strip is displayed"
            )
            self.assertTrue(
                v_tabstoolbar.rect["width"] > 0, "Vertical tab strip has > 0 width"
            )
        else:
            self.assertEqual(
                v_collapsed,
                "",
                "Vertical tab strip has expected collapsed attribute value",
            )

            self.assertTrue(
                h_tabstoolbar.is_displayed(), "Horizontal tab strip is displayed"
            )
            self.assertTrue(
                h_tabstoolbar.rect["height"] > 0, "Horizontal tab strip has > 0 height"
            )

            self.assertFalse(
                v_tabstoolbar.is_displayed(), "Vertical tab strip is not displayed"
            )
            self.assertEqual(
                v_tabstoolbar.rect["width"], 0, "Vertical tab strip has 0 width"
            )

    def test_vertical_widgets_in_area(self):
        # A clean startup in verticalTabs mode; we should get all the defaults
        self.restart_with_prefs(
            {
                "sidebar.revamp": True,
                "sidebar.verticalTabs": True,
                customization_pref: None,
                snapshot_pref: None,
            }
        )
        horiz_tab_ids = self.get_area_widgets("AREA_TABSTRIP")
        vertical_tab_ids = self.get_area_widgets("AREA_VERTICAL_TABSTRIP")

        self.assertEqual(
            len(horiz_tab_ids),
            0,
            msg="The horizontal tabstrip area is empty",
        )
        self.assertEqual(
            len(vertical_tab_ids),
            1,
            msg="The vertical tabstrip area has a single widget in it",
        )

        self.check_tabs_toolbar_visibilities("vertical")

        # Check we're able to recover if we initialize with vertical tabs enabled
        # and no saved pref for the horizontal tab strip placements
        self.marionette.set_pref("sidebar.verticalTabs", False)

        horiz_tab_ids = self.get_area_widgets("AREA_TABSTRIP")
        vertical_tab_ids = self.get_area_widgets("AREA_VERTICAL_TABSTRIP")

        self.check_tabs_toolbar_visibilities("horizontal")

        # Make sure we ended up with sensible defaults
        self.assertEqual(
            horiz_tab_ids,
            [
                "firefox-view-button",
                "tabbrowser-tabs",
                "new-tab-button",
                "alltabs-button",
            ],
            msg="The tabstrip was populated with the expected defaults",
        )

        self.assertEqual(
            len(vertical_tab_ids),
            0,
            msg="The vertical tabstrip area was emptied",
        )

    def test_restore_tabstrip_customizations(self):
        fixture_prefs = {
            "sidebar.revamp": True,
            "sidebar.verticalTabs": False,
        }
        self.restart_with_prefs(
            {
                **fixture_prefs,
                customization_pref: None,
                snapshot_pref: None,
            }
        )

        # Add a widget at the start of the horizontal tabstrip
        # This is synchronous and should result in updating the UI and the saved state in uiCustomization pref
        self.marionette.execute_script(
            "CustomizableUI.addWidgetToArea('panic-button', CustomizableUI.AREA_TABSTRIP, 0)"
        )

        saved_state = json.loads(self.marionette.get_pref(customization_pref))
        horiz_tab_ids = self.get_area_widgets("AREA_TABSTRIP")
        self.assertTrue(
            "panic-button" in horiz_tab_ids, "The widget we added is in the tabstrip"
        )

        self.assertTrue(
            "panic-button" in saved_state["placements"]["TabsToolbar"],
            "The widget we added is included in the saved customization state",
        )

        # Restart with vertical tabs enabled, leaving the uiCustomizations prefs as-is
        # We want to ensure initialization puts us in a good state without needing user
        # input to trigger the orientation change
        fixture_prefs["sidebar.verticalTabs"] = True
        self.restart_with_prefs(fixture_prefs)

        saved_state = json.loads(self.marionette.get_pref(customization_pref))

        self.check_tabs_toolbar_visibilities("vertical")

        horiz_tab_ids = self.get_area_widgets("AREA_TABSTRIP")
        nav_bar_ids = self.get_area_widgets("AREA_NAVBAR")

        self.assertEqual(
            len(horiz_tab_ids),
            0,
            msg="The horizontal tabstrip area is empty",
        )
        self.assertTrue(
            "panic-button" in nav_bar_ids, "The widget we added has moved to the navbar"
        )

        # Restart with horizontal tabs enabled. We want to ensure customizing the
        # panic-button into the tabstrip is correctly restored at initialization,
        # without needing user-input to trigger the orientation change
        fixture_prefs["sidebar.verticalTabs"] = False
        self.restart_with_prefs(fixture_prefs)

        self.check_tabs_toolbar_visibilities("horizontal")

        horiz_tab_ids = self.get_area_widgets("AREA_TABSTRIP")

        self.assertEqual(
            horiz_tab_ids[0],
            "panic-button",
            msg="The customization was preserved after restarting in horizontal tabs mode",
        )

    def test_preserve_visibility_pref_after_restart(self):
        fixture_prefs = {
            "sidebar.revamp": True,
            "sidebar.verticalTabs": True,
            "sidebar.visibility": "hide-sidebar",
        }
        self.restart_with_prefs(
            {
                **fixture_prefs,
                customization_pref: None,
                snapshot_pref: None,
            }
        )

        pref_value = self.marionette.execute_script(
            """
            return Services.prefs.getStringPref("sidebar.visibility", null);
        """
        )
        self.assertEqual(pref_value, "hide-sidebar")

        # Restart with no user visibility pref. We should get the default for vertical tabs
        # which is always-show
        fixture_prefs["sidebar.visibility"] = None
        self.restart_with_prefs(fixture_prefs)

        pref_value = self.marionette.execute_script(
            """
            return Services.prefs.getStringPref("sidebar.visibility", null);
        """
        )
        self.assertEqual(pref_value, "always-show")

        # Restart with vertical tabs disabled. We should get the default for horizontal tabs
        # which is hide-sidebar

        fixture_prefs["sidebar.visibility"] = None
        fixture_prefs["sidebar.verticalTabs"] = False
        self.restart_with_prefs(fixture_prefs)

        pref_value = self.marionette.execute_script(
            """
            return Services.prefs.getStringPref("sidebar.visibility", null);
        """
        )
        self.assertEqual(pref_value, "hide-sidebar")

    def test_hide_drag_to_pin_promo_if_horizontal_tabs_pinned(self):
        # Pin a tab using the horizontal tabstrip.
        self.restart_with_prefs(
            {
                "sidebar.revamp": False,
                "sidebar.verticalTabs": False,
            }
        )
        self.marionette.execute_async_script(
            """
            let resolve = arguments[0];
            let tab = gBrowser.selectedTab;
            tab.addEventListener("TabPinned", resolve, { once: true });
            gBrowser.pinTab(tab);
            """
        )

        # Switch to vertical tabs.
        self.marionette.execute_script(
            """
            Services.prefs.setBoolPref("sidebar.verticalTabs", true);
            """
        )

        promo_card = self.marionette.find_element(By.ID, "drag-to-pin-promo-card")
        self.assertFalse(
            promo_card.is_displayed(), "Drag-to-pin promo card is not displayed."
        )
