import gpxpy
from playwright.sync_api import Page, expect
from sqlalchemy import select

from testutils import extract_and_upload
from fietsboek import models


def disable_cache(page: Page):
    """Disable HTTP caching for the given page."""
    # A little workaround, as there is no direct HTTP cache setting:
    #     Enabling routing disables http cache.
    page.route("**", lambda route: route.continue_())


def test_transformer_zero_elevation_disabled(page: Page, playwright_helper, tmp_path, dbaccess):
    playwright_helper.login()

    page.goto("/")
    page.get_by_text("Upload").click()

    extract_and_upload(page, "Synthetic_Zero_Elevation.gpx.gz", tmp_path)

    page.locator(".btn", has_text="Upload").click()

    # Expect early (here and in the other tests) to ensure that the backend has
    # caught up with executing the transformer. Otherwise it might happen that
    # we read the database while the request is not finished yet.
    expect(page.locator("#detailsUphill")).to_contain_text("167.7 m")
    new_track_id = int(page.url.rsplit("/", 1)[1])
    track = dbaccess.execute(select(models.Track).filter_by(id=new_track_id)).scalar_one()

    assert track.cache.uphill > 160


def test_transformer_zero_elevation_enabled(page: Page, playwright_helper, tmp_path, dbaccess):
    playwright_helper.login()

    page.goto("/")
    page.get_by_text("Upload").click()

    extract_and_upload(page, "Synthetic_Zero_Elevation.gpx.gz", tmp_path)

    page.locator("#transformer-heading-1 .accordion-button").click()
    page.locator("#transformer-1.collapse.show").wait_for()
    page.locator("#transformer-enabled-1").check()

    page.locator(".btn", has_text="Upload").click()

    expect(page.locator("#detailsUphill")).to_contain_text("0 m")
    new_track_id = int(page.url.rsplit("/", 1)[1])
    track = dbaccess.execute(select(models.Track).filter_by(id=new_track_id)).scalar_one()

    assert track.cache.uphill < 0.1


def test_transformer_zero_elevation_edited(page: Page, playwright_helper, tmp_path, dbaccess):
    disable_cache(page)
    playwright_helper.login()

    page.goto("/")
    page.get_by_text("Upload").click()

    extract_and_upload(page, "Synthetic_Zero_Elevation.gpx.gz", tmp_path)

    page.locator(".btn", has_text="Upload").click()

    page.locator(".btn", has_text="Edit").click()

    page.locator("#transformer-heading-1 .accordion-button").click()
    page.locator("#transformer-1.collapse.show").wait_for()
    page.locator("#transformer-enabled-1").check()

    page.locator(".btn", has_text="Save").click()

    expect(page.locator("#detailsUphill")).to_contain_text("0 m")
    track_id = int(page.url.rsplit("/", 1)[1])
    track = dbaccess.execute(select(models.Track).filter_by(id=track_id)).scalar_one()

    assert track.cache.uphill < 0.1


def test_transformer_steep_slope_disabled(page: Page, playwright_helper, tmp_path, dbaccess):
    playwright_helper.login()

    page.goto("/")
    page.get_by_text("Upload").click()

    extract_and_upload(page, "Synthetic_Steep_Slope.gpx.gz", tmp_path)

    page.locator(".btn", has_text="Upload").click()

    expect(page.locator("#detailsUphill")).to_contain_text("61.54 m")
    new_track_id = int(page.url.rsplit("/", 1)[1])
    track = dbaccess.execute(select(models.Track).filter_by(id=new_track_id)).scalar_one()

    assert track.cache.uphill > 60


def test_transformer_steep_slope_enabled(page: Page, playwright_helper, tmp_path, dbaccess):
    playwright_helper.login()

    page.goto("/")
    page.get_by_text("Upload").click()

    extract_and_upload(page, "Synthetic_Steep_Slope.gpx.gz", tmp_path)

    page.locator("#transformer-heading-1 .accordion-button").click()
    page.locator("#transformer-1.collapse.show").wait_for()
    page.locator("#transformer-enabled-1").check()

    page.locator(".btn", has_text="Upload").click()

    expect(page.locator("#detailsUphill")).to_contain_text("1.2 m")
    new_track_id = int(page.url.rsplit("/", 1)[1])
    track = dbaccess.execute(select(models.Track).filter_by(id=new_track_id)).scalar_one()

    assert track.cache.uphill < 2


def test_transformer_steep_slope_edited(page: Page, playwright_helper, tmp_path, dbaccess):
    disable_cache(page)
    playwright_helper.login()

    page.goto("/")
    page.get_by_text("Upload").click()

    extract_and_upload(page, "Synthetic_Steep_Slope.gpx.gz", tmp_path)

    page.locator(".btn", has_text="Upload").click()

    page.locator(".btn", has_text="Edit").click()

    page.locator("#transformer-heading-1 .accordion-button").click()
    page.locator("#transformer-1.collapse.show").wait_for()
    page.locator("#transformer-enabled-1").check()

    page.locator(".btn", has_text="Save").click()

    expect(page.locator("#detailsUphill")).to_contain_text("1.2 m")
    track_id = int(page.url.rsplit("/", 1)[1])
    track = dbaccess.execute(select(models.Track).filter_by(id=track_id)).scalar_one()

    assert track.cache.uphill < 2


def test_transformer_elevation_jump_enabled(page: Page, playwright_helper, tmp_path, data_manager):
    playwright_helper.login()

    page.goto("/")
    page.get_by_text("Upload").click()

    extract_and_upload(page, "Elevation_Jump.gpx.gz", tmp_path)

    page.locator("#transformer-heading-2 .accordion-button").click()
    page.locator("#transformer-2.collapse.show").wait_for()
    page.locator("#transformer-enabled-2").check()

    page.locator(".btn", has_text="Upload").click()

    page.locator(".alert", has_text="Upload successful").wait_for()

    new_track_id = int(page.url.rsplit("/", 1)[1])
    data = data_manager.open(new_track_id)

    gpx = gpxpy.parse(data.decompress_gpx())
    points = iter(gpx.walk(only_points=True))
    next(points)
    for prev_point, point in zip(gpx.walk(only_points=True), points):
        # The given GPX has a jump of 94 between two consecutive points, so
        # here we assert that that jump is gone.
        assert abs(prev_point.elevation - point.elevation) < 10.0