import sys
from pathlib import Path

import pytest
from hypothesis import HealthCheck, assume, given, settings
from hypothesis import strategies as st

from dvcx.client.local import FileClient
from tests.utils import uppercase_scheme

non_null_text = st.text(
    alphabet=st.characters(blacklist_categories=["Cc", "Cs"]), min_size=1
)


@settings(suppress_health_check=[HealthCheck.function_scoped_fixture], deadline=None)
@given(rel_path=non_null_text)
def test_parse_url(cloud_test_catalog, rel_path, cloud_type):
    if cloud_type == "file":
        assume(not rel_path.startswith("/"))
    bucket_uri = cloud_test_catalog.src_uri
    url = f"{bucket_uri}/{rel_path}"
    catalog = cloud_test_catalog.catalog
    client, rel_part = catalog.parse_url(url)
    if cloud_type == "file":
        root_uri = FileClient.root_path().as_uri()
        assert client.uri == root_uri
        assert rel_part == url[len(root_uri) :]
    else:
        assert client.uri == bucket_uri
        assert rel_part == rel_path


@settings(suppress_health_check=[HealthCheck.function_scoped_fixture], deadline=None)
@given(rel_path=non_null_text)
def test_parse_url_uppercase_scheme(cloud_test_catalog, rel_path, cloud_type):
    if cloud_type == "file":
        assume(not rel_path.startswith("/"))
    bucket_uri = cloud_test_catalog.src_uri
    bucket_uri_upper = uppercase_scheme(bucket_uri)
    url = f"{bucket_uri_upper}/{rel_path}"
    catalog = cloud_test_catalog.catalog
    client, rel_part = catalog.parse_url(url)
    if cloud_type == "file":
        root_uri = FileClient.root_path().as_uri()
        assert client.uri == root_uri
        assert rel_part == url[len(root_uri) :]
    else:
        assert client.uri == bucket_uri
        assert rel_part == rel_path


@pytest.mark.parametrize("cloud_type", ["file"], indirect=True)
def test_parse_file_absolute_path_without_protocol(cloud_test_catalog):
    catalog = cloud_test_catalog.catalog
    working_dir = Path().absolute()
    root_uri = FileClient.root_path().as_uri()
    client, rel_part = catalog.parse_url(str(working_dir / Path("animals")))
    working_dir = Path().absolute()
    root_uri = FileClient.root_path().as_uri()
    assert client.uri == root_uri
    assert rel_part == (working_dir / Path("animals")).as_uri()[len(root_uri) :]


@pytest.mark.parametrize("cloud_type", ["file"], indirect=True)
def test_parse_file_relative_path_multiple_dirs_back(cloud_test_catalog):
    catalog = cloud_test_catalog.catalog
    client, rel_part = catalog.parse_url("../../animals")
    root_uri = FileClient.root_path().as_uri()
    assert client.uri == root_uri
    assert (
        rel_part
        == (Path().absolute().parents[1] / Path("animals")).as_uri()[len(root_uri) :]
    )


@pytest.mark.parametrize("cloud_type", ["file"], indirect=True)
@pytest.mark.parametrize("url", ["./animals", "animals"])
def test_parse_file_relative_path_working_dir(cloud_test_catalog, url):
    catalog = cloud_test_catalog.catalog
    client, rel_part = catalog.parse_url(url)
    root_uri = FileClient.root_path().as_uri()
    assert client.uri == root_uri
    assert rel_part == (Path().absolute() / Path("animals")).as_uri()[len(root_uri) :]


@pytest.mark.parametrize("cloud_type", ["file"], indirect=True)
def test_parse_file_relative_path_home_dir(cloud_test_catalog):
    if sys.platform == "win32":
        # home dir shortcut is not available on windows
        pytest.skip()
    catalog = cloud_test_catalog.catalog
    client, rel_part = catalog.parse_url("~/animals")
    root_uri = FileClient.root_path().as_uri()
    assert client.uri == root_uri
    assert rel_part == (Path().home() / Path("animals")).as_uri()[len(root_uri) :]
