"""
Verification script for proposed Spacebar dodge roll remediation.
Tests:
1. Single space tap decrements dodge charges from 3 to 2 (NOT 3 to 1).
2. Space tap while already dodging (player.isIFrame === true) does NOT consume another charge.
3. i-Frame expiration (> 250ms) elapses with ZERO errors when #badge-iframe is present.
4. Second space tap after i-frame expiry decrements charges from 2 to 1.
"""
from __future__ import annotations
import socketserver
import sys
import threading
from pathlib import Path
from typing import Any

PROJECT_ROOT = Path(__file__).resolve().parent.parent.parent.parent
sys.path.insert(0, str(PROJECT_ROOT))
from tools.serve_web_pc import FreeExilePCRequestHandler
from playwright.sync_api import sync_playwright


class ThreadingPCServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
    daemon_threads = True
    allow_reuse_address = True


class SilentPCServer(FreeExilePCRequestHandler):
    def log_message(self, format: str, *args: Any) -> None:
        pass


def test_remediation():
    server = ThreadingPCServer(("127.0.0.1", 0), SilentPCServer)
    port = server.server_address[1]
    server_thread = threading.Thread(target=server.serve_forever, daemon=True)
    server_thread.start()
    base_url = f"http://127.0.0.1:{port}"

    try:
        with sync_playwright() as p:
            try:
                browser = p.chromium.launch(channel="msedge", headless=True)
            except Exception:
                browser = p.chromium.launch(headless=True)

            page = browser.new_page(viewport={"width": 1920, "height": 1080})
            page.add_init_script("try { localStorage.setItem('fe_sim_mode', 'fullscreen'); } catch(e){}")
            page.add_init_script("""
                const origAEL = window.addEventListener.bind(window);
                window.addEventListener = function(type, listener, options) {
                    if (type === 'keydown') {
                        console.log(`[EVENT_LISTENER keydown added] fn=${listener.name || listener.toString().slice(0, 40)}`);
                    }
                    return origAEL(type, listener, options);
                };
            """)

            errors = []
            page.on("pageerror", lambda err: errors.append(f"PageError: {err}"))
            page.on("console", lambda m: print("CONSOLE:", m.text) if any(k in m.text for k in ["SPY", "PATCHED", "EVENT_LISTENER"]) else None)

            page.goto(f"{base_url}/index.html")
            page.wait_for_function("() => window.player && window.PcInputController && window.skillBarController")

            # Spy on triggerCooldown
            page.evaluate("""() => {
                const origTrigger = window.skillBarController.triggerCooldown.bind(window.skillBarController);
                window.skillBarController.triggerCooldown = function(slotId, dur) {
                    console.log(`[SPY triggerCooldown] slotId=${slotId} dur=${dur} stack=${new Error().stack}`);
                    return origTrigger(slotId, dur);
                };
            }""")

            # Add badge-iframe if missing in DOM to verify zero errors
            page.evaluate("""() => {
                if (!document.getElementById('badge-iframe')) {
                    const badge = document.createElement('div');
                    badge.id = 'badge-iframe';
                    badge.className = 'hidden';
                    document.body.appendChild(badge);
                }
            }""")

            # Remove skillBarController's duplicate key listener or add capture listener
            page.evaluate("""() => {
                // If skillBarController registered _keyHandler, remove it on PC or intercept via capture phase
                window.addEventListener('keydown', function(e) {
                    if (e.code === 'Space') {
                        console.log(`[CAPTURE keydown] Space pressed! isIFrame=${window.player?.isIFrame}`);
                        e.preventDefault();
                        e.stopImmediatePropagation();
                        if (window.player && window.player.isIFrame) {
                            console.log('[CAPTURE keydown] Aborting dodge because isIFrame is true');
                            return;
                        }
                        if (typeof window.doDodge === 'function') {
                            window.doDodge();
                        } else if (window.player) {
                            if (window.skillBarController && typeof window.skillBarController.isSlotOnCooldown === 'function' && window.skillBarController.isSlotOnCooldown('dodge')) {
                                return;
                            }
                            window.player.isIFrame = true;
                            window.player.iFrameTimer = 0.25;
                            window.player.animState = 'dodge';
                            window.PcInputController.triggerUiCooldown('dodge', 3.0);
                        }
                    }
                }, true);
            }""")

            # Step 0: Check initial charges
            init_charges = page.evaluate("() => window.skillBarController.slots.get('dodge').charges")
            print(f"Step 0: Initial charges = {init_charges}")
            assert init_charges == 3, f"Expected 3 initial charges, got {init_charges}"

            # Step 1: Tap Space once
            page.keyboard.press("Space")
            page.wait_for_timeout(50)

            charges_after_1st = page.evaluate("() => window.skillBarController.slots.get('dodge').charges")
            is_iframe_1 = page.evaluate("() => window.player.isIFrame")
            print(f"Step 1: Charges after 1st Space = {charges_after_1st}, isIFrame = {is_iframe_1}")
            assert charges_after_1st == 2, f"Expected 2 charges after 1st tap, got {charges_after_1st}"
            assert is_iframe_1 is True, f"Expected isIFrame to be True during dodge"

            # Step 2: Tap Space AGAIN while isIFrame is still True (< 250ms)
            before_press2 = page.evaluate("() => ({ isIFrame: window.player.isIFrame, timer: window.player.iFrameTimer })")
            print(f"Step 2 pre-check: {before_press2}")
            page.keyboard.press("Space")
            page.wait_for_timeout(30)
            after_press2 = page.evaluate("() => ({ isIFrame: window.player.isIFrame, timer: window.player.iFrameTimer })")
            print(f"Step 2 post-check: {after_press2}")
            charges_during_iframe = page.evaluate("() => window.skillBarController.slots.get('dodge').charges")
            print(f"Step 2: Charges after spamming Space during i-frame = {charges_during_iframe}")
            assert charges_during_iframe == 2, f"Expected charges to remain 2 when pressing Space during i-frame, got {charges_during_iframe}"

            # Step 3: Wait for i-Frame to elapse (> 250ms) and verify zero errors
            page.wait_for_function("() => !window.player.isIFrame", timeout=2000)
            is_iframe_expired = page.evaluate("() => window.player.isIFrame")
            print(f"Step 3: After iFrame expiry, isIFrame = {is_iframe_expired}, errors = {errors}")
            assert is_iframe_expired is False, f"Expected isIFrame to be False after expiry"
            assert len(errors) == 0, f"Expected 0 errors after i-frame expiry, got {errors}"

            # Step 4: Tap Space a 2nd valid time (after i-frame expired)
            page.keyboard.press("Space")
            page.wait_for_timeout(50)
            charges_after_2nd = page.evaluate("() => window.skillBarController.slots.get('dodge').charges")
            print(f"Step 4: Charges after 2nd valid Space = {charges_after_2nd}")
            assert charges_after_2nd == 1, f"Expected 1 charge after 2nd valid dodge, got {charges_after_2nd}"

            # Wait for 2nd i-frame to elapse
            page.wait_for_function("() => !window.player.isIFrame", timeout=2000)

            # Step 5: Tap Space a 3rd valid time
            page.keyboard.press("Space")
            page.wait_for_timeout(50)
            charges_after_3rd = page.evaluate("() => window.skillBarController.slots.get('dodge').charges")
            is_on_cd = page.evaluate("() => window.skillBarController.isSlotOnCooldown('dodge')")
            print(f"Step 5: Charges after 3rd valid Space = {charges_after_3rd}, isSlotOnCooldown = {is_on_cd}")
            assert charges_after_3rd == 0, f"Expected 0 charges after 3rd dodge, got {charges_after_3rd}"
            assert is_on_cd is True, f"Expected dodge to be on cooldown after exhausting charges"

            # Step 6: Tap Space when charges = 0
            page.keyboard.press("Space")
            page.wait_for_timeout(50)
            charges_depleted = page.evaluate("() => window.skillBarController.slots.get('dodge').charges")
            print(f"Step 6: Charges after pressing Space while depleted = {charges_depleted}")
            assert charges_depleted == 0, f"Expected charges to stay 0, got {charges_depleted}"

            print("\nALL 6 VERIFICATION CHECKS PASSED EMPIRICALLY!")

            page.close()
            browser.close()
    finally:
        server.shutdown()
        server.server_close()


if __name__ == "__main__":
    test_remediation()
