"""Selenium UI tests — green-path smoke tests for the dashboard.

Requires:
  - Dashboard running at http://localhost:8000 (make up DEV=1)
  - Chrome installed (headless mode, no display needed)
  - selenium pip package

Run:
  SELENIUM_UI=1 pytest tests/functional/test_ui_selenium.py -v
"""

import os

import pytest

try:
    from selenium import webdriver
    from selenium.webdriver.chrome.options import Options
    from selenium.webdriver.common.by import By
    from selenium.webdriver.common.keys import Keys
    from selenium.webdriver.support import expected_conditions as EC
    from selenium.webdriver.support.ui import WebDriverWait

    HAS_SELENIUM = True
except ImportError:
    HAS_SELENIUM = False

# Skip entire module unless SELENIUM_UI=1 is set and Selenium is installed
pytestmark = pytest.mark.skipif(
    not HAS_SELENIUM or os.environ.get("SELENIUM_UI") != "1",
    reason="Selenium not installed or SELENIUM_UI not set to 1",
)

DASHBOARD_URL = os.environ.get("DASHBOARD_URL", "http://localhost:8000")


@pytest.fixture(scope="module")
def driver():
    """Headless Chrome WebDriver, shared across tests in this module."""
    opts = Options()
    opts.add_argument("--headless=new")
    opts.add_argument("--no-sandbox")
    opts.add_argument("--disable-dev-shm-usage")
    opts.add_argument("--disable-gpu")
    opts.add_argument("--window-size=1280,900")

    d = webdriver.Chrome(options=opts)
    d.implicitly_wait(5)
    yield d
    d.quit()


@pytest.fixture(autouse=True)
def _check_dashboard():
    """Skip all tests if the dashboard isn't reachable."""
    import httpx

    try:
        r = httpx.get(f"{DASHBOARD_URL}/health", timeout=5)
        if r.status_code != 200:
            pytest.skip("Dashboard not healthy")
    except Exception:
        pytest.skip("Dashboard not reachable at " + DASHBOARD_URL)


def _load_dashboard(driver):
    """Navigate to dashboard and wait for Timmy panel to load."""
    driver.get(DASHBOARD_URL)
    WebDriverWait(driver, 15).until(
        EC.presence_of_element_located((By.XPATH, "//*[contains(text(), 'TIMMY INTERFACE')]"))
    )


def _wait_for_sidebar(driver):
    """Wait for the agent sidebar to finish its HTMX load."""
    WebDriverWait(driver, 15).until(
        EC.presence_of_element_located((By.XPATH, "//*[contains(text(), 'SWARM AGENTS')]"))
    )


def _has_registered_agents(driver):
    """Check if there are any registered agent cards in the sidebar."""
    cards = driver.find_elements(By.CSS_SELECTOR, ".mc-agent-card")
    return len(cards) > 0


def _send_chat_and_wait(driver, message):
    """Send a chat message and wait for the NEW agent response.

    Returns the number of agent messages before and after sending.
    """
    existing = len(driver.find_elements(By.CSS_SELECTOR, ".chat-message.agent"))

    inp = driver.find_element(By.CSS_SELECTOR, "input[name='message']")
    inp.send_keys(message)
    inp.send_keys(Keys.RETURN)

    # Wait for a NEW agent response (not one from a prior test)
    WebDriverWait(driver, 30).until(
        lambda d: len(d.find_elements(By.CSS_SELECTOR, ".chat-message.agent")) > existing
    )

    return existing


# ── Page load tests ─────────────────────────────────────────────────────────


class TestPageLoad:
    """Dashboard loads and shows expected structure."""

    def test_homepage_loads(self, driver):
        driver.get(DASHBOARD_URL)
        assert driver.title != ""

    def test_header_visible(self, driver):
        _load_dashboard(driver)
        header = driver.find_element(By.CSS_SELECTOR, ".mc-header, header, nav")
        assert header.is_displayed()

    def test_sidebar_loads(self, driver):
        _load_dashboard(driver)
        _wait_for_sidebar(driver)

    def test_timmy_panel_loads(self, driver):
        _load_dashboard(driver)

    def test_chat_input_exists(self, driver):
        _load_dashboard(driver)
        inp = driver.find_element(By.CSS_SELECTOR, "input[name='message']")
        assert inp.is_displayed()
        assert "timmy" in inp.get_attribute("placeholder").lower()

    def test_send_button_exists(self, driver):
        _load_dashboard(driver)
        btn = driver.find_element(By.CSS_SELECTOR, "button.mc-btn-send")
        assert btn.is_displayed()
        assert "SEND" in btn.text

    def test_health_panel_loads(self, driver):
        _load_dashboard(driver)
        WebDriverWait(driver, 10).until(
            EC.presence_of_element_located((By.XPATH, "//*[contains(text(), 'SYSTEM HEALTH')]"))
        )


# ── Chat interaction tests ──────────────────────────────────────────────────


class TestChatInteraction:
    """Send a single message and verify all chat-related behaviors at once.

    We only send ONE message to avoid spamming Ollama and crashing the browser.
    """

    def test_chat_roundtrip(self, driver):
        """Full chat roundtrip: send message, get response, input clears, chat scrolls."""
        _load_dashboard(driver)

        # Wait for page to be ready
        WebDriverWait(driver, 10).until(
            lambda d: d.execute_script("return document.readyState") == "complete"
        )

        existing_agents = len(driver.find_elements(By.CSS_SELECTOR, ".chat-message.agent"))

        inp = driver.find_element(By.CSS_SELECTOR, "input[name='message']")
        inp.send_keys("hello from selenium")
        inp.send_keys(Keys.RETURN)

        # 1. User bubble appears immediately
        WebDriverWait(driver, 5).until(
            EC.presence_of_element_located((By.CSS_SELECTOR, ".chat-message.user"))
        )

        # 2. Agent response arrives
        WebDriverWait(driver, 30).until(
            lambda d: len(d.find_elements(By.CSS_SELECTOR, ".chat-message.agent")) > existing_agents
        )

        # 3. Input cleared (regression test)
        # Already waited for agent response via WebDriverWait above
        inp = driver.find_element(By.CSS_SELECTOR, "input[name='message']")
        assert inp.get_attribute("value") == "", "Input should be empty after sending"

        # 4. Chat scrolled to bottom (regression test)
        chat_log = driver.find_element(By.ID, "chat-log")
        scroll_top = driver.execute_script("return arguments[0].scrollTop", chat_log)
        scroll_height = driver.execute_script("return arguments[0].scrollHeight", chat_log)
        client_height = driver.execute_script("return arguments[0].clientHeight", chat_log)

        if scroll_height > client_height:
            gap = scroll_height - scroll_top - client_height
            assert gap < 50, f"Chat not scrolled to bottom (gap: {gap}px)"


# ── Task panel tests ────────────────────────────────────────────────────────


class TestTaskPanel:
    """Task creation panel works correctly."""

    def test_task_panel_via_url(self, driver):
        """Task panel loads correctly when navigated to directly."""
        driver.get(f"{DASHBOARD_URL}/swarm/tasks/panel")
        WebDriverWait(driver, 10).until(
            EC.presence_of_element_located((By.XPATH, "//*[contains(text(), 'CREATE TASK')]"))
        )

    def test_task_panel_has_form(self, driver):
        """Task creation panel has description and agent fields."""
        driver.get(f"{DASHBOARD_URL}/swarm/tasks/panel")
        WebDriverWait(driver, 10).until(
            EC.presence_of_element_located((By.XPATH, "//*[contains(text(), 'CREATE TASK')]"))
        )

        driver.find_element(By.CSS_SELECTOR, "textarea[name='description']")
        driver.find_element(By.CSS_SELECTOR, "select[name='agent_id']")

    def test_task_button_on_agent_card(self, driver):
        """If agents are registered, TASK button on agent card opens task panel."""
        _load_dashboard(driver)
        _wait_for_sidebar(driver)

        if not _has_registered_agents(driver):
            pytest.skip("No agents registered — TASK button not available")

        task_btn = driver.find_element(
            By.XPATH,
            "//div[contains(@class, 'mc-agent-card')]//button[contains(text(), 'TASK')]",
        )
        task_btn.click()

        WebDriverWait(driver, 10).until(
            EC.presence_of_element_located((By.XPATH, "//*[contains(text(), 'CREATE TASK')]"))
        )


# ── Agent sidebar tests ─────────────────────────────────────────────────────


class TestAgentSidebar:
    """Agent sidebar displays correctly."""

    def test_sidebar_header_shows(self, driver):
        _load_dashboard(driver)
        _wait_for_sidebar(driver)
        header = driver.find_element(By.XPATH, "//*[contains(text(), 'SWARM AGENTS')]")
        assert header.is_displayed()

    def test_sidebar_shows_status_when_agents_exist(self, driver):
        """If agents are registered, cards show status dots."""
        _load_dashboard(driver)
        _wait_for_sidebar(driver)

        if not _has_registered_agents(driver):
            pytest.skip("No agents registered — skipping card test")

        cards = driver.find_elements(By.CSS_SELECTOR, ".mc-agent-card")
        for card in cards:
            dots = card.find_elements(By.CSS_SELECTOR, ".status-dot")
            assert len(dots) >= 1, "Agent card should show a status dot"

    def test_no_agents_fallback(self, driver):
        """When no agents registered, sidebar shows fallback message."""
        _load_dashboard(driver)
        _wait_for_sidebar(driver)

        if _has_registered_agents(driver):
            pytest.skip("Agents are registered — fallback not shown")

        body = driver.find_element(By.CSS_SELECTOR, ".mc-sidebar").text
        assert "NO AGENTS REGISTERED" in body


# ── Navigation tests ────────────────────────────────────────────────────────


class TestNavigation:
    """Basic navigation flows work end-to-end."""

    def test_clear_chat_button(self, driver):
        _load_dashboard(driver)
        clear_btn = driver.find_element(By.XPATH, "//button[contains(text(), 'CLEAR')]")
        assert clear_btn.is_displayed()

    def test_health_endpoint_returns_200(self, driver):
        driver.get(f"{DASHBOARD_URL}/health")
        assert "ok" in driver.page_source

    def test_nav_links_visible(self, driver):
        _load_dashboard(driver)
        links = driver.find_elements(By.CSS_SELECTOR, ".mc-desktop-nav .mc-test-link")
        assert len(links) >= 3, "Navigation should have multiple links"
