from datetime import timedelta

import pytest
import gpxpy
from markupsafe import Markup

from testutils import load_gpx_asset
from fietsboek import util


@pytest.mark.parametrize('md_source, expected', [
    ("**foobar**", Markup("<p><strong>foobar</strong></p>")),
    ("*foobar*", Markup("<p><em>foobar</em></p>")),
    ("# foobar", Markup("<h1>foobar</h1>")),
    ("<script>alert('evil')</script>", Markup("")),
    ("<x-script>alert('evil')</x-script>", Markup("<p>alert('evil')</p>")),
])
def test_safe_markdown(md_source, expected):
    assert util.safe_markdown(md_source) == expected


@pytest.mark.parametrize('timestamp, fixed', [
    ("2022-03-14T13:37:42", "2022-03-14T13:37:42"),
    ("2022-03-14T13:37:42Z", "2022-03-14T13:37:42+00:00"),
    ("2022-03-14T13:37:42+02:00", "2022-03-14T13:37:42+02:00"),
])
def test_fix_iso_timestamp(timestamp, fixed):
    assert util.fix_iso_timestamp(timestamp) == fixed


@pytest.mark.parametrize('delta, multiple, expected', [
    (
        timedelta(seconds=0),
        timedelta(seconds=1),
        timedelta(seconds=0),
    ),
    (
        timedelta(minutes=42),
        timedelta(minutes=15),
        timedelta(minutes=45),
    ),
    (
        timedelta(minutes=33),
        timedelta(minutes=15),
        timedelta(minutes=30),
    ),
    (
        timedelta(minutes=-12),
        timedelta(minutes=15),
        timedelta(minutes=-15),
    ),
    (
        timedelta(minutes=-31),
        timedelta(minutes=15),
        timedelta(minutes=-30),
    ),
])
def test_round_timedelta_to_multiple(delta, multiple, expected):
    assert util.round_timedelta_to_multiple(delta, multiple) == expected


@pytest.mark.parametrize('gpx_file, offset', [
    ("Teasi_1.gpx.gz", timedelta(hours=2)),
])
def test_guess_gpx_timezone(gpx_file, offset):
    parsed_gpx = gpxpy.parse(load_gpx_asset(gpx_file))
    timezone = util.guess_gpx_timezone(parsed_gpx)
    # Here we hope (and assume) that utcoffset is ignored. This is true for
    # datetime.timezone objects, but may not be for other datetime.tzinfo
    # instances.
    assert timezone.utcoffset(None) == offset


@pytest.mark.parametrize('gpx_file', [
    'Teasi_1.gpx.gz',
    'MyTourbook_1.gpx.gz',
    'Synthetic_WT2.gpx.gz',
    'Synthetic_BRouter_1.gpx.gz',
])
def test_tour_metadata(gpx_file):
    # Here we simply make sure that we do not crash the metadata extraction
    # function.
    gpx_data = load_gpx_asset(gpx_file)
    assert util.tour_metadata(gpx_data) is not None


@pytest.mark.parametrize('mps, kph', [(1, 3.6), (10, 36)])
def test_mps_to_kph(mps, kph):
    assert util.mps_to_kph(mps) == pytest.approx(kph, 0.1)

@pytest.mark.parametrize('num_bytes, expected', [
    (1, '1 B'),
    (1023, '1023 B'),
    (1024, '1.0 KiB'),
    (1536, '1.5 KiB'),
    (1024 ** 2, '1.0 MiB'),
    (1024 ** 3, '1.0 GiB'),
    (0, '0 B'),
    # Negative sizes in itself are a bit weird, but they make sense as the
    # difference between two size values, so they should still work.
    (-1, '-1 B'),
    (-1024, '-1.0 KiB'),
])
def test_human_size(num_bytes, expected):
    assert util.human_size(num_bytes) == expected


def test_tile_url(app_request):
    route_url = util.tile_url(app_request, "tile-proxy", provider="bobby")

    assert "{x}" in route_url
    assert "{y}" in route_url
    assert "{z}" in route_url
    assert "bobby" in route_url