"""
End-to-end tests for web client with headless browser.
"""

import os
import socketserver
import threading
from http.server import HTTPServer, SimpleHTTPRequestHandler
from pathlib import Path

import pytest

CLIENT_DIR = Path(__file__).parent.parent.parent / "client"


class ThreadedHTTPServer(socketserver.ThreadingMixIn, HTTPServer):
    """Threaded HTTP server for handling concurrent requests."""

    daemon_threads = True


@pytest.fixture(scope="module")
def http_server():
    """Start a local HTTP server for the client."""
    os.chdir(CLIENT_DIR)

    handler = SimpleHTTPRequestHandler
    server = ThreadedHTTPServer(("127.0.0.1", 0), handler)
    port = server.server_address[1]

    thread = threading.Thread(target=server.serve_forever, daemon=True)
    thread.start()

    yield f"http://127.0.0.1:{port}"

    server.shutdown()


class TestWebClient:
    """Tests for the web client using Playwright."""

    @pytest.fixture(autouse=True)
    def setup_browser(self):
        """Set up browser for tests."""
        pytest.importorskip("playwright")
        from playwright.sync_api import sync_playwright

        self.playwright = sync_playwright().start()
        self.browser = self.playwright.chromium.launch(headless=True)
        self.context = self.browser.new_context()
        self.page = self.context.new_page()

        yield

        self.page.close()
        self.context.close()
        self.browser.close()
        self.playwright.stop()

    def test_client_loads(self, http_server):
        """Web client loads without errors."""
        response = self.page.goto(http_server)
        assert response.status == 200, f"Page load failed with status {response.status}"

        self.page.wait_for_load_state("domcontentloaded")

        content = self.page.content()
        assert "<canvas" in content, "Canvas element not found in page"

        canvas = self.page.locator("#terminal")
        assert canvas.count() > 0, "Canvas not found"

    def test_status_shows_connecting(self, http_server):
        """Status shows connecting initially."""
        self.page.goto(http_server)
        self.page.wait_for_load_state("domcontentloaded")

        status = self.page.locator("#status")
        assert status.count() > 0, "Status element not found"

    def test_canvas_has_dimensions(self, http_server):
        """Canvas has correct dimensions after load."""
        self.page.goto(http_server)
        self.page.wait_for_load_state("domcontentloaded")

        canvas = self.page.locator("#terminal")
        assert canvas.count() > 0, "Canvas not found"

    def test_no_console_errors_on_load(self, http_server):
        """No JavaScript errors on page load (websocket errors are expected without server)."""
        js_errors = []

        def handle_console(msg):
            if msg.type == "error":
                text = msg.text
                if "WebSocket" not in text:
                    js_errors.append(text)

        self.page.on("console", handle_console)
        self.page.goto(http_server)
        self.page.wait_for_load_state("domcontentloaded")

        assert len(js_errors) == 0, f"JavaScript errors: {js_errors}"


class TestWebClientProtocol:
    """Tests for WebSocket protocol handling in client."""

    @pytest.fixture(autouse=True)
    def setup_browser(self):
        """Set up browser for tests."""
        pytest.importorskip("playwright")
        from playwright.sync_api import sync_playwright

        self.playwright = sync_playwright().start()
        self.browser = self.playwright.chromium.launch(headless=True)
        self.context = self.browser.new_context()
        self.page = self.context.new_page()

        yield

        self.page.close()
        self.context.close()
        self.browser.close()
        self.playwright.stop()

    def test_websocket_reconnection(self, http_server):
        """Client attempts reconnection on disconnect."""
        self.page.goto(http_server)
        self.page.wait_for_load_state("domcontentloaded")

        status = self.page.locator("#status")
        assert status.count() > 0, "Status element not found"
