import platform
import re

from playwright.sync_api import expect

from umap.models import DataLayer

from ..base import DataLayerFactory


def test_should_have_fieldset_for_layer_type_properties(page, live_server, tilelayer):
    page.goto(f"{live_server.url}/en/map/new/")

    # Open DataLayers list
    page.get_by_title("Manage layers").click()

    # Create a layer
    page.get_by_title("Add a layer").click()
    page.locator("input[name=name]").fill("Layer 1")

    select = page.locator(".panel.on .umap-field-type select")
    expect(select).to_be_visible()

    choropleth_header = page.get_by_text("Choropleth: settings")
    heat_header = page.get_by_text("Heatmap: settings")
    cluster_header = page.get_by_text("Clustered: settings")
    expect(choropleth_header).to_be_hidden()
    expect(heat_header).to_be_hidden()
    expect(cluster_header).to_be_hidden()

    # Switching to Choropleth should add a dedicated fieldset
    select.select_option("Choropleth")
    expect(choropleth_header).to_be_visible()
    expect(heat_header).to_be_hidden()
    expect(cluster_header).to_be_hidden()

    select.select_option("Heat")
    expect(heat_header).to_be_visible()
    expect(choropleth_header).to_be_hidden()
    expect(cluster_header).to_be_hidden()

    select.select_option("Cluster")
    expect(cluster_header).to_be_visible()
    expect(choropleth_header).to_be_hidden()
    expect(heat_header).to_be_hidden()

    select.select_option("Default")
    expect(choropleth_header).to_be_hidden()
    expect(heat_header).to_be_hidden()
    expect(cluster_header).to_be_hidden()


def test_cancel_deleting_datalayer_should_restore(
    live_server, openmap, datalayer, page
):
    page.goto(f"{live_server.url}{openmap.get_absolute_url()}?edit")
    page.get_by_title("Open browser").click()
    layers = page.locator(".umap-browser .datalayer")
    markers = page.locator(".leaflet-marker-icon")
    expect(layers).to_have_count(1)
    expect(markers).to_have_count(1)
    page.get_by_role("link", name="Manage layers").click()
    page.locator(".panel.right").get_by_title("Delete layer").click()
    page.get_by_role("button", name="OK").click()
    expect(markers).to_have_count(0)
    expect(page.get_by_text("test datalayer")).to_be_hidden()
    page.get_by_role("button", name="Cancel edits").click()
    page.locator("dialog").get_by_role("button", name="OK").click()
    expect(markers).to_have_count(1)
    expect(page.locator(".umap-browser").get_by_text("test datalayer")).to_be_visible()


def test_can_clone_datalayer(live_server, openmap, login, datalayer, page):
    page.goto(f"{live_server.url}{openmap.get_absolute_url()}?edit")
    page.get_by_title("Open browser").click()
    layers = page.locator(".umap-browser .datalayer")
    markers = page.locator(".leaflet-marker-icon")
    expect(layers).to_have_count(1)
    expect(markers).to_have_count(1)
    page.get_by_role("link", name="Manage layers").click()
    page.locator(".panel.right").get_by_title("Edit", exact=True).click()
    page.get_by_text("Advanced actions").click()
    page.get_by_role("button", name="Clone").click()
    expect(layers).to_have_count(2)
    expect(markers).to_have_count(2)


def test_can_change_icon_class(live_server, openmap, page):
    data = {
        "type": "FeatureCollection",
        "features": [
            {
                "type": "Feature",
                "properties": {"name": "Point 4"},
                "geometry": {"type": "Point", "coordinates": [0.856934, 45.290347]},
            },
        ],
    }
    DataLayerFactory(map=openmap, data=data)
    page.goto(f"{live_server.url}{openmap.get_absolute_url()}?edit#6/45.3/1")
    expect(page.locator(".umap-div-icon")).to_be_visible()
    page.get_by_role("link", name="Manage layers").click()
    expect(page.locator(".umap-circle-icon")).to_be_hidden()
    page.locator(".panel.right").get_by_title("Edit", exact=True).click()
    page.get_by_text("Shape properties").click()
    page.locator(".umap-field-iconClass button.define").click()
    page.get_by_text("Circle", exact=True).click()
    expect(page.locator(".umap-circle-icon")).to_be_visible()
    expect(page.locator(".umap-div-icon")).to_be_hidden()


def test_can_change_name(live_server, openmap, page, datalayer):
    page.goto(
        f"{live_server.url}{openmap.get_absolute_url()}?edit&onLoadPanel=databrowser"
    )
    page.get_by_role("link", name="Manage layers").click()
    page.locator(".panel.right").get_by_title("Edit", exact=True).click()
    expect(page.locator(".umap-is-dirty")).to_be_hidden()
    page.locator('input[name="name"]').click()
    page.locator('input[name="name"]').press("Control+a")
    page.locator('input[name="name"]').fill("new name")
    expect(page.locator(".umap-browser .datalayer")).to_contain_text("new name")
    expect(page.locator("body")).to_have_class(re.compile(".*umap-is-dirty.*"))
    with page.expect_response(re.compile(".*/datalayer/update/.*")):
        page.get_by_role("button", name="Save").click()
    saved = DataLayer.objects.last()
    assert saved.name == "new name"
    expect(page.locator(".umap-is-dirty")).to_be_hidden()


def test_can_create_new_datalayer(live_server, openmap, page, datalayer):
    """
    Test the creation and editing of a new datalayer.

    This test verifies that:
    1. A new datalayer can be created and saved.
    2. The newly created datalayer appears in the UI and is saved in the database.
    3. Editing the same datalayer updates it instead of creating a new one.
    4. The UI reflects the changes and the database is updated correctly.
    5. The 'dirty' state of the map is managed correctly during these operations.
    """

    page.goto(
        f"{live_server.url}{openmap.get_absolute_url()}?edit&onLoadPanel=databrowser"
    )
    page.get_by_role("link", name="Manage layers").click()
    page.get_by_role("button", name="Add a layer").click()
    page.locator('input[name="name"]').click()
    page.locator('input[name="name"]').fill("Layer A")
    expect(page.get_by_text("Layer A")).to_be_visible()
    with page.expect_response(re.compile(".*/datalayer/create/.*")):
        page.get_by_role("button", name="Save").click()
    assert DataLayer.objects.count() == 2
    saved = DataLayer.objects.last()
    assert saved.name == "Layer A"
    expect(page.locator(".umap-is-dirty")).to_be_hidden()
    # Edit again, it should not create a new datalayer
    page.get_by_role("link", name="Manage layers").click()
    page.locator(".panel.right").get_by_title("Edit", exact=True).first.click()
    page.locator('input[name="name"]').click()
    page.locator('input[name="name"]').fill("Layer A with a new name")
    expect(page.get_by_text("Layer A with a new name")).to_be_visible()
    page.get_by_role("button", name="Save").click()
    with page.expect_response(re.compile(".*/datalayer/update/.*")):
        page.get_by_role("button", name="Save").click()
    assert DataLayer.objects.count() == 2
    saved = DataLayer.objects.last()
    assert saved.name == "Layer A with a new name"
    expect(page.locator(".umap-is-dirty")).to_be_hidden()


def test_can_restore_version(live_server, openmap, page, datalayer):
    page.goto(f"{live_server.url}{openmap.get_absolute_url()}?edit")
    marker = page.locator(".leaflet-marker-icon")
    expect(marker).to_have_class(re.compile(".*umap-ball-icon.*"))
    marker.click(modifiers=["Shift"])
    page.get_by_text("Shape properties").click()
    page.locator("#umap-feature-shape-properties").get_by_text("Default").click()
    with page.expect_response(re.compile(".*/datalayer/update/.*")):
        page.get_by_role("button", name="Save").click()
    expect(marker).to_have_class(re.compile(".*umap-div-icon.*"))
    page.get_by_role("link", name="Manage layers").click()
    page.locator(".panel.right").get_by_title("Edit", exact=True).click()
    page.get_by_text("Versions").click()
    page.get_by_role("button", name="Restore this version").last.click()
    page.get_by_role("button", name="OK").click()
    expect(marker).to_have_class(re.compile(".*umap-ball-icon.*"))


def test_can_edit_layer_on_ctrl_shift_click(live_server, openmap, page, datalayer):
    modifier = "Meta" if platform.system() == "Darwin" else "Control"
    page.goto(f"{live_server.url}{openmap.get_absolute_url()}?edit")
    page.locator(".leaflet-marker-icon").click(modifiers=[modifier, "Shift"])
    expect(page.get_by_text("Layer properties")).to_be_visible()


def test_deleting_datalayer_should_remove_from_browser_and_layers_list(
    live_server, openmap, datalayer, page
):
    page.goto(f"{live_server.url}{openmap.get_absolute_url()}?edit")
    panel = page.locator(".panel.left")
    edit_panel = page.locator(".panel.right")
    page.get_by_title("Open browser").click()
    page.get_by_role("link", name="Manage layers").click()
    expect(panel.get_by_text("test datalayer")).to_be_visible()
    expect(edit_panel.get_by_text("test datalayer")).to_be_visible()
    page.locator(".panel.right").get_by_title("Delete layer").click()
    page.get_by_role("button", name="OK").click()
    expect(panel.get_by_text("test datalayer")).to_be_hidden()
    expect(edit_panel.get_by_text("test datalayer")).to_be_hidden()


def test_deleting_datalayer_should_remove_from_caption(
    live_server, openmap, datalayer, page
):
    page.goto(f"{live_server.url}{openmap.get_absolute_url()}?edit")
    panel = page.locator(".panel.left")
    page.get_by_role("button", name="About").click()
    page.get_by_role("link", name="Manage layers").click()
    expect(panel.get_by_text("test datalayer")).to_be_visible()
    page.locator(".panel.right").get_by_title("Delete layer").click()
    page.get_by_role("button", name="OK").click()
    expect(panel.get_by_text("test datalayer")).to_be_hidden()


def test_can_edit_datalayer_name_in_list(live_server, openmap, datalayer, page):
    page.goto(f"{live_server.url}{openmap.get_absolute_url()}?edit")
    page.get_by_role("link", name="Manage layers").click()
    page.get_by_text("test datalayer").click()
    page.get_by_text("test datalayer").fill("test datalayer foobar")
    page.get_by_role("button", name="Open browser").click()
    expect(
        page.locator(".panel.left").get_by_text("test datalayer foobar")
    ).to_be_visible()
