import typing

import pytest

from libvcs.sync.hg import HgSync
from libvcs.url.base import MatcherRegistry
from libvcs.url.hg import DEFAULT_MATCHERS, PIP_DEFAULT_MATCHERS, HgURL


class HgURLFixture(typing.NamedTuple):
    url: str
    is_valid: bool
    hg_url: HgURL


TEST_FIXTURES: list[HgURLFixture] = [
    HgURLFixture(
        url="https://bitbucket.com/vcs-python/libvcs",
        is_valid=True,
        hg_url=HgURL(
            url="https://bitbucket.com/vcs-python/libvcs",
            scheme="https",
            hostname="bitbucket.com",
            path="vcs-python/libvcs",
        ),
    ),
    HgURLFixture(
        url="https://bitbucket.com/vcs-python/libvcs",
        is_valid=True,
        hg_url=HgURL(
            url="https://bitbucket.com/vcs-python/libvcs",
            scheme="https",
            hostname="bitbucket.com",
            path="vcs-python/libvcs",
        ),
    ),
]


@pytest.mark.parametrize(
    "url,is_valid,hg_url",
    TEST_FIXTURES,
)
def test_hg_url(
    url: str,
    is_valid: bool,
    hg_url: HgURL,
    hg_repo: HgSync,
) -> None:
    url = url.format(local_repo=hg_repo.dir)
    hg_url.url = hg_url.url.format(local_repo=hg_repo.dir)

    assert HgURL.is_valid(url) == is_valid, f"{url} compatibility should be {is_valid}"
    assert HgURL(url) == hg_url


class HgURLKwargs(typing.TypedDict):
    url: str


class HgURLKwargsFixture(typing.NamedTuple):
    url: str
    is_valid: bool
    hg_url_kwargs: HgURLKwargs


#
#
# Extensibility: pip(1)
# w/ VCS prefixes, e.g. hg+https, hg+ssh, hg+file
# https://pip.pypa.io/en/stable/topics/vcs-support/
#
#
PIP_TEST_FIXTURES: list[HgURLKwargsFixture] = [
    HgURLKwargsFixture(
        url="hg+https://bitbucket.com/liuxinyu95/AlgoXY",
        is_valid=True,
        hg_url_kwargs=HgURLKwargs(url="hg+https://bitbucket.com/liuxinyu95/AlgoXY"),
    ),
    HgURLKwargsFixture(
        url="hg+ssh://hg@bitbucket.com:tony/AlgoXY",
        is_valid=True,
        hg_url_kwargs=HgURLKwargs(url="hg+ssh://hg@bitbucket.com:tony/AlgoXY"),
    ),
    HgURLKwargsFixture(
        url="hg+file://{local_repo}",
        is_valid=True,
        hg_url_kwargs=HgURLKwargs(url="hg+file://{local_repo}"),
    ),
    # Incompatible
    HgURLKwargsFixture(
        url="hg+ssh://hg@bitbucket.com/tony/AlgoXY",
        is_valid=True,
        hg_url_kwargs=HgURLKwargs(url="hg+ssh://hg@bitbucket.com/tony/AlgoXY"),
    ),
]


@pytest.mark.parametrize(
    "url,is_valid,hg_url_kwargs",
    PIP_TEST_FIXTURES,
)
def test_hg_url_extension_pip(
    url: str,
    is_valid: bool,
    hg_url_kwargs: HgURLKwargs,
    hg_repo: HgSync,
) -> None:
    class HgURLWithPip(HgURL):
        matchers: MatcherRegistry = MatcherRegistry(
            _matchers={m.label: m for m in [*DEFAULT_MATCHERS, *PIP_DEFAULT_MATCHERS]}
        )

    hg_url_kwargs["url"] = hg_url_kwargs["url"].format(local_repo=hg_repo.dir)
    url = url.format(local_repo=hg_repo.dir)
    hg_url = HgURLWithPip(**hg_url_kwargs)
    hg_url.url = hg_url.url.format(local_repo=hg_repo.dir)

    assert (
        HgURL.is_valid(url) != is_valid
    ), f"{url} compatibility should work with core, expects {not is_valid}"
    assert (
        HgURLWithPip.is_valid(url) == is_valid
    ), f"{url} compatibility should be {is_valid}"
    assert HgURLWithPip(url) == hg_url


class ToURLFixture(typing.NamedTuple):
    hg_url: HgURL
    expected: str


@pytest.mark.parametrize(
    "hg_url,expected",
    [
        ToURLFixture(
            expected="https://bitbucket.com/vcs-python/libvcs",
            hg_url=HgURL(
                url="https://bitbucket.com/vcs-python/libvcs",
                scheme="https",
                hostname="bitbucket.com",
                path="vcs-python/libvcs",
            ),
        ),
        ToURLFixture(
            expected="https://bitbucket.com/vcs-python/libvcs",
            hg_url=HgURL(
                url="https://bitbucket.com/vcs-python/libvcs",
                scheme="https",
                hostname="bitbucket.com",
                path="vcs-python/libvcs",
            ),
        ),
        #
        # SCP-style URLs:
        # e.g. 'ssh://hg@example.com/foo/bar'
        #
        ToURLFixture(
            expected="ssh://hg@bitbucket.com/liuxinyu95/AlgoXY",
            hg_url=HgURL(
                url="ssh://hg@bitbucket.com/liuxinyu95/AlgoXY",
                user="hg",
                scheme="ssh",
                hostname="bitbucket.com",
                path="liuxinyu95/AlgoXY",
            ),
        ),
        ToURLFixture(
            expected="ssh://username@bitbucket.com/vcs-python/libvcs",
            hg_url=HgURL(
                url="username@bitbucket.com/vcs-python/libvcs",
                user="username",
                scheme="ssh",
                hostname="bitbucket.com",
                path="vcs-python/libvcs",
            ),
        ),
    ],
)
def test_hg_to_url(
    expected: str,
    hg_url: HgURL,
    hg_repo: HgSync,
) -> None:
    """Test HgURL.to_url()"""
    hg_url.url = hg_url.url.format(local_repo=hg_repo.dir)

    assert hg_url.to_url() == expected
