# Copyright 2024 Pex project contributors.
# Licensed under the Apache License, Version 2.0 (see LICENSE).

import os.path
import re

import pytest

from pex.compatibility import PY2
from pex.pip.version import PipVersion, PipVersionValue
from pex.targets import LocalInterpreter
from pex.typing import TYPE_CHECKING
from testing import IntegResults
from testing.cli import run_pex3

if TYPE_CHECKING:
    from typing import Any


def assert_lock_sync(
    lock,  # type: str
    pip_version,  # type: PipVersionValue
    *extra_args  # type: str
):
    # type: (...) -> IntegResults
    result = run_pex3(
        "lock",
        "sync",
        "--style",
        "strict",
        "--pip-version",
        str(pip_version),
        "bloom-filter2>=2.0.0",
        "--indent",
        "2",
        "--lock",
        lock,
        *extra_args
    )
    result.assert_success()
    return result


TARGET = LocalInterpreter.create()
PLATFORM_TAG = TARGET.platform.tag

skip_if_py2 = pytest.mark.skipif(
    PY2, reason="The bloom-filter2 project only claims support for Python 3.x"
)


@skip_if_py2
@pytest.mark.parametrize(
    "pip_version",
    [
        pytest.param(version, id=str(version))
        for version in PipVersion.values()
        if version < PipVersion.v23_2 and version.requires_python_applies(TARGET)
    ],
)
def test_sync_version_mismatch_old_pip(
    pip_version,  # type: PipVersionValue
    tmpdir,  # type: Any
):
    # type: (...) -> None

    lock = os.path.join(str(tmpdir), "lockfile.json")
    assert_lock_sync(lock, pip_version)

    result = assert_lock_sync(lock, pip_version)
    assert re.match(
        r"^{lead_in}\n"
        r"    \+ http.*{wheel}\n"
        r"    - http.*{sdist}$\n".format(
            lead_in=re.escape(
                "Updates for lock generated by {platform_tag}:\n"
                "  Updated bloom-filter2 2 artifacts:".format(platform_tag=PLATFORM_TAG)
            ),
            wheel=re.escape("bloom_filter2-2.0.0-py3-none-any.whl"),
            sdist=re.escape("bloom-filter2-2.0.0-1.tar.gz"),
        ),
        result.error,
    ), result.error

    result = assert_lock_sync(lock, pip_version)
    assert (
        "No updates for lock generated by {platform_tag}.\n".format(platform_tag=PLATFORM_TAG)
        == result.error
    )

    result = assert_lock_sync(lock, pip_version)
    assert (
        "No updates for lock generated by {platform_tag}.\n".format(platform_tag=PLATFORM_TAG)
        == result.error
    )


@skip_if_py2
@pytest.mark.parametrize(
    "pip_version",
    [
        pytest.param(version, id=str(version))
        for version in PipVersion.values()
        if version >= PipVersion.v23_2 and version.requires_python_applies(TARGET)
    ],
)
def test_sync_version_mismatch_new_pip(
    pip_version,  # type: PipVersionValue
    tmpdir,  # type: Any
):
    # type: (...) -> None

    lock = os.path.join(str(tmpdir), "lockfile.json")
    assert_lock_sync(lock, pip_version)

    result = assert_lock_sync(lock, pip_version)
    assert (
        "No updates for lock generated by {platform_tag}.\n".format(platform_tag=PLATFORM_TAG)
        == result.error
    )

    result = assert_lock_sync(lock, pip_version)
    assert (
        "No updates for lock generated by {platform_tag}.\n".format(platform_tag=PLATFORM_TAG)
        == result.error
    )


@skip_if_py2
@pytest.mark.parametrize(
    "pip_version",
    [
        pytest.param(version, id=str(version))
        for version in PipVersion.values()
        if version.requires_python_applies(TARGET)
    ],
)
def test_sync_version_mismatch_prefer_binary_all_pips(
    pip_version,  # type: PipVersionValue
    tmpdir,  # type: Any
):
    # type: (...) -> None

    lock = os.path.join(str(tmpdir), "lockfile.json")
    assert_lock_sync(lock, pip_version, "--prefer-binary")

    result = assert_lock_sync(lock, pip_version)
    assert (
        "No updates for lock generated by {platform_tag}.\n".format(platform_tag=PLATFORM_TAG)
        == result.error
    )

    result = assert_lock_sync(lock, pip_version)
    assert (
        "No updates for lock generated by {platform_tag}.\n".format(platform_tag=PLATFORM_TAG)
        == result.error
    )
