from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys

from .base import FunctionalTest
from apps.applets.models import Applet
from apps.drama.models import GameEvent, record
from apps.epic.models import DeckVariant, Room
from apps.lyric.models import Token, User


class GameKitTest(FunctionalTest):
    """Game Kit <dialog>: opens from footer, shows token cards, dismisses."""

    def setUp(self):
        super().setUp()
        self.earthman, _ = DeckVariant.objects.get_or_create(
            slug="earthman",
            defaults={"name": "Earthman Deck", "card_count": 108, "is_default": True},
        )
        self.create_pre_authenticated_session("gamer@kit.io")
        self.gamer = User.objects.get(email="gamer@kit.io")
        self.gamer.equipped_deck = self.earthman
        self.gamer.save(update_fields=["equipped_deck"])
        self.gamer.unlocked_decks.add(self.earthman)
        self.token = self.gamer.tokens.filter(token_type=Token.COIN).first()
        self.room = Room.objects.create(name="Kit Room", owner=self.gamer)
        self.gate_url = self.live_server_url + f"/gameboard/room/{self.room.id}/gate/"

    def test_kit_btn_in_footer_opens_dialog(self):
        self.browser.get(self.gate_url)
        kit_btn = self.wait_for(
            lambda: self.browser.find_element(By.ID, "id_kit_btn")
        )
        self.assertTrue(kit_btn.is_displayed())
        kit_btn.click()
        self.wait_for(
            lambda: self.assertTrue(
                self.browser.find_element(By.ID, "id_kit_bag_dialog").is_displayed()
            )
        )

    def test_kit_dialog_shows_token_cards(self):
        self.browser.get(self.gate_url)
        self.browser.find_element(By.ID, "id_kit_btn").click()
        self.wait_for(
            lambda: self.browser.find_element(
                By.CSS_SELECTOR,
                f"#id_kit_bag_dialog [data-token-id='{self.token.id}']",
            )
        )

    def test_kit_dialog_closes_on_escape(self):
        self.browser.get(self.gate_url)
        self.browser.find_element(By.ID, "id_kit_btn").click()
        self.wait_for(
            lambda: self.assertTrue(
                self.browser.find_element(By.ID, "id_kit_bag_dialog").is_displayed()
            )
        )
        dialog = self.browser.find_element(By.ID, "id_kit_bag_dialog")
        dialog.send_keys(Keys.ESCAPE)
        self.wait_for(
            lambda: self.assertFalse(
                self.browser.find_element(By.ID, "id_kit_bag_dialog").is_displayed()
            )
        )

    def test_kit_btn_visible_outside_room(self):
        self.browser.get(self.live_server_url + "/")
        kit_btn = self.wait_for(
            lambda: self.browser.find_element(By.ID, "id_kit_btn")
        )
        self.assertTrue(kit_btn.is_displayed())

    def test_kit_dialog_shows_equipped_deck(self):
        """New user auto-gets Earthman equipped; kit bar shows its deck card."""
        self.browser.get(self.gate_url)
        self.browser.find_element(By.ID, "id_kit_btn").click()
        self.wait_for(
            lambda: self.browser.find_element(
                By.CSS_SELECTOR,
                f"#id_kit_bag_dialog .kit-bag-deck[data-deck-id='{self.gamer.equipped_deck.pk}']",
            )
        )

    def test_kit_dialog_always_shows_dice_placeholder(self):
        self.browser.get(self.gate_url)
        self.browser.find_element(By.ID, "id_kit_btn").click()
        self.wait_for(
            lambda: self.browser.find_element(
                By.CSS_SELECTOR,
                "#id_kit_bag_dialog .kit-bag-placeholder",
            )
        )

    def test_kit_dialog_deck_tooltip_shows_name_count_availability_and_stock_version(self):
        self.browser.get(self.gate_url)
        self.browser.find_element(By.ID, "id_kit_btn").click()
        deck_el = self.wait_for(
            lambda: self.browser.find_element(
                By.CSS_SELECTOR, "#id_kit_bag_dialog .kit-bag-deck"
            )
        )
        # Dispatch mouseenter via JS — more reliable than ActionChains in headless CI
        self.browser.execute_script(
            "arguments[0].dispatchEvent(new Event('mouseenter'))", deck_el
        )
        tooltip = self.browser.find_element(
            By.CSS_SELECTOR, "#id_kit_bag_dialog .kit-bag-deck .tt"
        )
        self.wait_for(lambda: self.assertTrue(tooltip.is_displayed()))
        text = tooltip.text
        self.assertIn("Earthman", text)
        self.assertIn("(Default)", text)
        self.assertIn("108", text)
        self.assertIn("Stock version", text)


class PronounsAppletFlowTest(FunctionalTest):
    """End-to-end profile-wide pronoun flip:

    The same provenance prose ("X embodies as {poss} Significator …") rendered
    on both the per-room scroll AND the billboard's Most Recent Scroll applet
    should re-render when the user flips their pronouns ideology via the
    Pronouns applet on the Game Kit page. The test starts on a billscroll seeing
    "their" cognates (default pluralism), navigates to Game Kit, clicks the
    bawlmorese card → guard portal → OK, then verifies the Most Recent Scroll
    on the billboard AND the room's billscroll both render "yos" cognates.
    """

    def setUp(self):
        super().setUp()
        # Billboard applets — page renders blank without these
        for slug, name, cols, rows in [
            ("my-scrolls",         "My Scrolls",         4, 3),
            ("my-buds",         "My Buds",         4, 3),
            ("most-recent-scroll", "Most Recent Scroll", 8, 6),
        ]:
            Applet.objects.get_or_create(
                slug=slug,
                defaults={"name": name, "grid_cols": cols, "grid_rows": rows, "context": "billboard"},
            )
        # Game Kit applets — including the new Pronouns applet
        for slug, name in [
            ("gk-trinkets", "Trinkets"),
            ("gk-tokens",   "Tokens"),
            ("gk-decks",    "Card Decks"),
            ("gk-dice",     "Dice Sets"),
            ("pronouns",    "Pronouns"),
        ]:
            Applet.objects.get_or_create(
                slug=slug,
                defaults={"name": name, "grid_cols": 3, "grid_rows": 3, "context": "game-kit"},
            )
        self.create_pre_authenticated_session("disco@pronouns.io")
        self.user = User.objects.get(email="disco@pronouns.io")
        self.room = Room.objects.create(name="Pronoun Chamber", owner=self.user)
        # Seed a SIG_READY event so both scrolls have prose to render
        record(
            self.room, GameEvent.SIG_READY, actor=self.user,
            card_name="Maid of Brands", corner_rank="M",
            suit_icon="fa-wand-sparkles",
        )
        self.scroll_url   = self.live_server_url + f"/billboard/room/{self.room.id}/scroll/"
        self.billboard_url = self.live_server_url + "/billboard/"
        self.game_kit_url  = self.live_server_url + "/gameboard/game-kit/"

    def _scroll_text(self):
        return self.browser.find_element(By.ID, "id_drama_scroll").text

    def _most_recent_text(self):
        return self.browser.find_element(By.ID, "id_applet_most_recent_scroll").text

    def test_pronoun_flip_propagates_to_billscroll_and_most_recent(self):
        # 1. Start on the room's billscroll — default pluralism reads "their".
        self.browser.get(self.scroll_url)
        self.wait_for(lambda: self.browser.find_element(By.ID, "id_drama_scroll"))
        self.assertIn("embodies as their Significator", self._scroll_text())

        # 2. Navigate to the Game Kit page and find the bawlmorese card.
        self.browser.get(self.game_kit_url)
        bawlmorese_card = self.wait_for(
            lambda: self.browser.find_element(
                By.CSS_SELECTOR, ".gk-pronoun-card[data-pronoun='bawlmorese']"
            )
        )

        # 3. Click the card → guard portal becomes active w. the slash-trio
        #    preview ("yo/yo/yos") above OK|NVM.
        self.browser.execute_script("arguments[0].click()", bawlmorese_card)
        self.wait_for(
            lambda: self.browser.find_element(
                By.CSS_SELECTOR, "#id_guard_portal.active"
            )
        )
        portal = self.browser.find_element(By.ID, "id_guard_portal")
        self.assertIn("Set pronoun preference?", portal.text)
        self.assertIn("yo/yo/yos", portal.text)

        # 4. Click OK — first-time bawlmorese unlocks the Baltimorean Note, so
        #    the server returns 200 w. a Brief payload (no reload — the banner
        #    would be lost). Wait for the banner to confirm the commit landed
        #    before navigating away.
        portal.find_element(By.CSS_SELECTOR, ".guard-yes").click()
        self.wait_for(
            lambda: self.browser.find_element(By.CSS_SELECTOR, ".note-banner")
        )

        # 5. Navigate to the Billboard — Most Recent Scroll applet must now
        #    read "yos" cognates, not "their".
        self.browser.get(self.billboard_url)
        self.wait_for(
            lambda: self.browser.find_element(By.ID, "id_applet_most_recent_scroll")
        )
        self.assertIn("embodies as yos Significator", self._most_recent_text())
        self.assertNotIn("embodies as their Significator", self._most_recent_text())

        # 6. And back on the per-room billscroll — same prose, same flip.
        self.browser.get(self.scroll_url)
        self.wait_for(lambda: self.browser.find_element(By.ID, "id_drama_scroll"))
        self.assertIn("embodies as yos Significator", self._scroll_text())
        self.assertNotIn("embodies as their Significator", self._scroll_text())
