import pytest

pytest.importorskip("playwright")

from bokeh.models import Tooltip
from playwright.sync_api import expect

import panel as pn

from panel.tests.util import serve_component, wait_until
from panel.widgets import TooltipIcon
from panel.widgets.indicators import Gauge

pytestmark = pytest.mark.ui


@pytest.mark.parametrize(
    "value", ["Test", Tooltip(content="Test", position="right")], ids=["str", "Tooltip"]
)
def test_plaintext_tooltip(page, value):
    tooltip_icon = TooltipIcon(value="Test")

    serve_component(page, tooltip_icon)

    icon = page.locator(".bk-icon")
    expect(icon).to_have_count(1)
    tooltip = page.locator(".bk-tooltip-content")
    expect(tooltip).to_have_count(0)

    # Hovering over the icon should show the tooltip
    page.hover(".bk-icon")
    tooltip = page.locator(".bk-tooltip-content")
    expect(tooltip).to_have_count(1)
    expect(tooltip).to_have_text("Test")

    # Removing hover should hide the tooltip
    page.hover("body")
    tooltip = page.locator(".bk-tooltip-content")
    expect(tooltip).to_have_count(0)

    # Clicking the icon should show the tooltip
    page.click(".bk-icon")
    tooltip = page.locator(".bk-tooltip-content")
    expect(tooltip).to_have_count(1)

    # Removing the hover should keep the tooltip
    page.hover("body")
    tooltip = page.locator(".bk-tooltip-content")
    expect(tooltip).to_have_count(1)

    # Clicking should remove the tooltip
    page.click("body")
    tooltip = page.locator(".bk-tooltip-content")
    expect(tooltip).to_have_count(0)


def test_tooltip_text_updates(page):
    tooltip_icon = TooltipIcon(value="Test")

    serve_component(page, tooltip_icon)

    icon = page.locator(".bk-icon")
    expect(icon).to_have_count(1)
    tooltip = page.locator(".bk-tooltip-content")
    expect(tooltip).to_have_count(0)

    # Hovering over the icon should show the tooltip
    page.hover(".bk-icon")
    tooltip = page.locator(".bk-tooltip-content")
    expect(tooltip).to_have_count(1)
    expect(tooltip).to_have_text("Test")

    tooltip_icon.value = "Updated"

    def hover():
        page.hover(".bk-icon")
        visible = page.locator(".bk-tooltip-content").count() == 1
        page.hover("body")
        return visible
    wait_until(hover, page)

    page.hover(".bk-icon")
    tooltip = page.locator(".bk-tooltip-content")
    expect(tooltip).to_have_count(1)
    expect(tooltip).to_have_text("Updated")


def _wait_for_echarts(page, timeout=30000):
    """Wait for the ECharts JS module to be loaded on the page.

    Gauge renders via ECharts. serve_component only waits for the Panel
    websocket and networkidle, not for the ECharts module fetch. On slow
    CI runners the canvas can appear well after networkidle, so polling
    for `window.echarts` is the reliable readiness signal.
    """
    page.wait_for_function("typeof window.echarts !== 'undefined'", timeout=timeout)


def test_gauge_renders(page):
    gauge = Gauge(label="Speed", value=75, bounds=(0, 200))

    serve_component(page, gauge)

    _wait_for_echarts(page)
    expect(page.locator("canvas")).to_have_count(1, timeout=10000)


def test_gauge_does_not_crash_other_widgets(page):
    """Regression test: Gauge should not crash other widgets on the page."""
    gauge = Gauge(label="G", value=50, bounds=(0, 100))
    slider = pn.widgets.IntSlider(label="Slider", value=25, start=0, end=100)
    col = pn.Column(gauge, slider)

    serve_component(page, col)

    # The slider must render even if Gauge is on the same page
    expect(page.locator(".noUi-target")).to_have_count(1, timeout=10000)
    # Gauge canvas should also eventually render
    _wait_for_echarts(page)
    expect(page.locator("canvas")).to_have_count(1, timeout=10000)


def test_gauge_value_update(page):
    gauge = Gauge(label="G", value=25, bounds=(0, 100))

    serve_component(page, gauge)

    _wait_for_echarts(page)
    expect(page.locator("canvas")).to_have_count(1, timeout=10000)

    # Update value and verify no crash
    gauge.value = 75

    # Canvas should still be present after update
    expect(page.locator("canvas")).to_have_count(1, timeout=5000)
