"""Functional tests for the CAST SKY overlay — natal chart entry."""

import json as _json

from selenium.webdriver.common.by import By

from apps.applets.models import Applet
from apps.epic.models import GateSlot, Room
from apps.lyric.models import User

from .base import FunctionalTest


_PICK_SKY_CHART_FIXTURE = {
    "planets": {
        "Sun":  {"sign": "Gemini", "degree": 66.7, "retrograde": False},
        "Moon": {"sign": "Taurus", "degree": 43.0, "retrograde": False},
    },
    "houses": {"cusps": [180, 210, 240, 270, 300, 330, 0, 30, 60, 90, 120, 150],
               "asc": 180.0, "mc": 90.0},
    "elements": {"Fire": 1, "Water": 0, "Stone": 2, "Air": 4, "Time": 1, "Space": 1},
    "aspects": [],
    "distinctions": {str(i): 0 for i in range(1, 13)},
    "house_system": "O",
    "timezone": "America/New_York",
}


def _make_sky_select_room():
    """Minimal SKY_SELECT room — just enough for the overlay to render."""
    email = "founder@test.io"
    gamer, _ = User.objects.get_or_create(email=email)
    room = Room.objects.create(name="Sky Test Room", table_status=Room.SKY_SELECT, owner=gamer)
    # Put the founder in slot 1 so the view recognises them as a participant
    slot = room.gate_slots.get(slot_number=1)
    slot.gamer = gamer
    slot.status = GateSlot.FILLED
    slot.save()
    room.gate_status = Room.OPEN
    room.save()
    return room, gamer, email


class PickSkyLocalStorageTest(FunctionalTest):
    """CAST SKY form fields persist to localStorage."""

    def setUp(self):
        super().setUp()
        Applet.objects.get_or_create(
            slug="new-game", defaults={"name": "New Game", "context": "gameboard"}
        )
        Applet.objects.get_or_create(
            slug="my-games", defaults={"name": "My Games", "context": "gameboard"}
        )
        self.room, self.founder, self.founder_email = _make_sky_select_room()
        self.room_url = (
            self.live_server_url + f"/gameboard/room/{self.room.id}/"
        )

    def _open_overlay(self):
        btn = self.wait_for(
            lambda: self.browser.find_element(By.ID, "id_pick_sky_btn")
        )
        self.browser.execute_script("arguments[0].click()", btn)
        self.wait_for(
            lambda: self.browser.find_element(By.ID, "id_sky_overlay")
        )

    def _fill_form(self):
        """Set date, lat, lon directly (bypasses Nominatim network call)."""
        self.browser.execute_script(
            "document.getElementById('id_nf_date').value = '2008-05-27';"
            "document.getElementById('id_nf_lat').value  = '38.3754';"
            "document.getElementById('id_nf_lon').value  = '-76.6955';"
            "document.getElementById('id_nf_place').value = 'Morganza, MD';"
            "document.getElementById('id_nf_tz').value   = 'America/New_York';"
        )
        # Fire input events so the save listener triggers
        self.browser.execute_script("""
            ['id_nf_date','id_nf_lat','id_nf_lon','id_nf_place','id_nf_tz'].forEach(id => {
                const el = document.getElementById(id);
                el.dispatchEvent(new Event('input', {bubbles: true}));
            });
        """)

    def _field_values(self):
        return self.browser.execute_script("""
            return {
                date:  document.getElementById('id_nf_date').value,
                lat:   document.getElementById('id_nf_lat').value,
                lon:   document.getElementById('id_nf_lon').value,
                place: document.getElementById('id_nf_place').value,
                tz:    document.getElementById('id_nf_tz').value,
            };
        """)

    # ------------------------------------------------------------------ #
    # T1 — fields survive NVM (close + reopen, same page load)            #
    # ------------------------------------------------------------------ #

    def test_form_fields_repopulated_after_nvm(self):
        self.create_pre_authenticated_session(self.founder_email)
        self.browser.get(self.room_url)

        self._open_overlay()
        self._fill_form()

        # Close via NVM
        self.browser.find_element(By.ID, "id_sky_cancel").click()

        # Reopen
        self._open_overlay()

        values = self._field_values()
        self.assertEqual(values["date"], "2008-05-27")
        self.assertEqual(values["lat"],  "38.3754")
        self.assertEqual(values["lon"],  "-76.6955")
        self.assertEqual(values["place"], "Morganza, MD")
        self.assertEqual(values["tz"],   "America/New_York")

    # ------------------------------------------------------------------ #
    # T2 — fields survive a page refresh                                  #
    # ------------------------------------------------------------------ #

    def test_form_fields_repopulated_after_page_refresh(self):
        self.create_pre_authenticated_session(self.founder_email)
        self.browser.get(self.room_url)

        self._open_overlay()
        self._fill_form()

        # Refresh the page
        self.browser.refresh()

        self._open_overlay()

        values = self._field_values()
        self.assertEqual(values["date"], "2008-05-27")
        self.assertEqual(values["lat"],  "38.3754")
        self.assertEqual(values["lon"],  "-76.6955")
        self.assertEqual(values["place"], "Morganza, MD")
        self.assertEqual(values["tz"],   "America/New_York")




class PickSkyDelTest(FunctionalTest):
    """CAST SKY overlay gets a DEL btn at the wheel center: clicking opens the
    global guard portal; OK clears the wheel SVG, resets the form fields, &
    purges the localStorage entry that would otherwise rehydrate the form on
    the next overlay open / page refresh. No server hit (the wheel here is
    purely a preview — un-saved data lives only in localStorage)."""

    def setUp(self):
        super().setUp()
        Applet.objects.get_or_create(
            slug="new-game", defaults={"name": "New Game", "context": "gameboard"}
        )
        Applet.objects.get_or_create(
            slug="my-games", defaults={"name": "My Games", "context": "gameboard"}
        )
        self.room, self.founder, self.founder_email = _make_sky_select_room()
        self.room_url = self.live_server_url + f"/gameboard/room/{self.room.id}/"

    def _ls_key(self):
        # Mirrors the JS: 'sky-form:' + SAVE_URL  (overlay.dataset.saveUrl is
        # an absolute URL, so the LS key carries the full http://host:port… too)
        return self.browser.execute_script(
            "return 'sky-form:' + document.getElementById('id_sky_overlay').dataset.saveUrl;"
        )

    def test_del_clears_wheel_form_and_localstorage(self):
        self.create_pre_authenticated_session(self.founder_email)
        self.browser.get(self.room_url)

        # Open CAST SKY modal
        btn = self.wait_for(lambda: self.browser.find_element(By.ID, "id_pick_sky_btn"))
        self.browser.execute_script("arguments[0].click()", btn)
        self.wait_for(lambda: self.browser.find_element(By.ID, "id_sky_overlay"))

        # Mock /sky/preview so schedulePreview resolves & SkyWheel.draw paints
        # children into #id_sky_svg without hitting PySwiss.
        self.browser.execute_script("""
            const FIXTURE = """ + _json.dumps(_PICK_SKY_CHART_FIXTURE) + """;
            window._origFetch = window.fetch;
            window.fetch = function(url, opts) {
                if (typeof url === 'string' && url.includes('/sky/preview')) {
                    return Promise.resolve({ok:true, json:()=>Promise.resolve(FIXTURE)});
                }
                return window._origFetch(url, opts);
            };
        """)

        # Fill form → triggers schedulePreview → wheel renders
        self.browser.execute_script("""
            document.getElementById('id_nf_date').value = '2008-05-27';
            document.getElementById('id_nf_lat').value  = '38.3754';
            document.getElementById('id_nf_lon').value  = '-76.6955';
            document.getElementById('id_nf_place').value = 'Morganza, MD';
            document.getElementById('id_nf_tz').value   = 'America/New_York';
            document.getElementById('id_nf_date').dispatchEvent(
                new Event('input', {bubbles:true})
            );
        """)

        # Wait for the wheel to render (svg has children)
        self.wait_for(lambda: self.assertTrue(
            self.browser.find_elements(By.CSS_SELECTOR, "#id_sky_svg > *")
        ))

        # localStorage was populated by _saveForm during typing
        ls_key = self._ls_key()
        self.assertIsNotNone(self.browser.execute_script(
            f"return localStorage.getItem({_json.dumps(ls_key)});"
        ))

        # DEL btn → guard portal → OK
        del_btn = self.browser.find_element(By.ID, "id_sky_delete_btn")
        del_btn.click()
        portal = self.wait_for(lambda: self.browser.find_element(By.ID, "id_guard_portal"))
        self.wait_for(lambda: self.assertIn("active", portal.get_attribute("class")))
        portal.find_element(By.CSS_SELECTOR, ".guard-yes").click()

        # After OK: SVG empty, form fields blank, localStorage entry purged,
        # and the DEL btn itself is gone — re-injection only happens on the
        # next wheel paint, not while we sit on a freshly-cleared wheel.
        self.wait_for(lambda: self.assertFalse(
            self.browser.find_elements(By.CSS_SELECTOR, "#id_sky_svg > *"),
            "Wheel SVG should be cleared after DEL",
        ))
        self.assertFalse(
            self.browser.find_elements(By.ID, "id_sky_delete_btn"),
            "DEL btn should be removed from the DOM after clear",
        )
        values = self.browser.execute_script("""
            return {
                date:  document.getElementById('id_nf_date').value,
                lat:   document.getElementById('id_nf_lat').value,
                lon:   document.getElementById('id_nf_lon').value,
                place: document.getElementById('id_nf_place').value,
                tz:    document.getElementById('id_nf_tz').value,
            };
        """)
        self.assertEqual(values["date"], "")
        self.assertEqual(values["lat"], "")
        self.assertEqual(values["lon"], "")
        self.assertEqual(values["place"], "")
        self.assertEqual(values["tz"], "")
        self.assertIsNone(self.browser.execute_script(
            f"return localStorage.getItem({_json.dumps(ls_key)});"
        ))
