from __future__ import annotations

import pytest

from commitizen.version_schemes import SemVer2, VersionProtocol
from tests.utils import VersionSchemeTestArgs


@pytest.mark.parametrize(
    "version_args, expected_version",
    [
        (
            VersionSchemeTestArgs(
                current_version="0.1.1",
                increment="PATCH",
                prerelease=None,
                prerelease_offset=0,
                devrelease=None,
            ),
            "0.1.2",
        ),
        (
            VersionSchemeTestArgs(
                current_version="0.1.1",
                increment="MINOR",
                prerelease=None,
                prerelease_offset=0,
                devrelease=None,
            ),
            "0.2.0",
        ),
        (
            VersionSchemeTestArgs(
                current_version="2.1.1",
                increment="MAJOR",
                prerelease=None,
                prerelease_offset=0,
                devrelease=None,
            ),
            "3.0.0",
        ),
        (
            VersionSchemeTestArgs(
                current_version="0.9.0",
                increment="PATCH",
                prerelease="alpha",
                prerelease_offset=0,
                devrelease=None,
            ),
            "0.9.1-alpha.0",
        ),
        (
            VersionSchemeTestArgs(
                current_version="0.9.0",
                increment="MINOR",
                prerelease="alpha",
                prerelease_offset=0,
                devrelease=None,
            ),
            "0.10.0-alpha.0",
        ),
        (
            VersionSchemeTestArgs(
                current_version="0.9.0",
                increment="MAJOR",
                prerelease="alpha",
                prerelease_offset=0,
                devrelease=None,
            ),
            "1.0.0-alpha.0",
        ),
        (
            VersionSchemeTestArgs(
                current_version="0.9.0",
                increment="MAJOR",
                prerelease="alpha",
                prerelease_offset=1,
                devrelease=None,
            ),
            "1.0.0-alpha.1",
        ),
        (
            VersionSchemeTestArgs(
                current_version="1.0.0-alpha.2",
                increment=None,
                prerelease="beta",
                prerelease_offset=0,
                devrelease=None,
            ),
            "1.0.0-beta.0",
        ),
        (
            VersionSchemeTestArgs(
                current_version="1.0.0-alpha.2",
                increment=None,
                prerelease="beta",
                prerelease_offset=1,
                devrelease=None,
            ),
            "1.0.0-beta.1",
        ),
        (
            VersionSchemeTestArgs(
                current_version="1.0.0-beta.1",
                increment=None,
                prerelease="rc",
                prerelease_offset=0,
                devrelease=None,
            ),
            "1.0.0-rc.0",
        ),
        (
            VersionSchemeTestArgs(
                current_version="1.0.0-rc.1",
                increment=None,
                prerelease="rc",
                prerelease_offset=0,
                devrelease=None,
            ),
            "1.0.0-rc.2",
        ),
        (
            VersionSchemeTestArgs(
                current_version="1.0.0-alpha.0",
                increment=None,
                prerelease="rc",
                prerelease_offset=0,
                devrelease=None,
            ),
            "1.0.0-rc.0",
        ),
        (
            VersionSchemeTestArgs(
                current_version="1.0.0-alpha.1",
                increment=None,
                prerelease="alpha",
                prerelease_offset=0,
                devrelease=None,
            ),
            "1.0.0-alpha.2",
        ),
        # weird_cases
        (
            VersionSchemeTestArgs(
                current_version="1.1",
                increment="PATCH",
                prerelease=None,
                prerelease_offset=0,
                devrelease=None,
            ),
            "1.1.1",
        ),
        (
            VersionSchemeTestArgs(
                current_version="1",
                increment="MINOR",
                prerelease=None,
                prerelease_offset=0,
                devrelease=None,
            ),
            "1.1.0",
        ),
        (
            VersionSchemeTestArgs(
                current_version="1",
                increment="MAJOR",
                prerelease=None,
                prerelease_offset=0,
                devrelease=None,
            ),
            "2.0.0",
        ),
        (
            VersionSchemeTestArgs(
                current_version="1-alpha.0",
                increment=None,
                prerelease="alpha",
                prerelease_offset=0,
                devrelease=None,
            ),
            "1.0.0-alpha.1",
        ),
        (
            VersionSchemeTestArgs(
                current_version="1-alpha.0",
                increment=None,
                prerelease="alpha",
                prerelease_offset=1,
                devrelease=None,
            ),
            "1.0.0-alpha.1",
        ),
        (
            VersionSchemeTestArgs(
                current_version="1",
                increment=None,
                prerelease="beta",
                prerelease_offset=0,
                devrelease=None,
            ),
            "1.0.0-beta.0",
        ),
        (
            VersionSchemeTestArgs(
                current_version="1",
                increment=None,
                prerelease="beta",
                prerelease_offset=1,
                devrelease=None,
            ),
            "1.0.0-beta.1",
        ),
        (
            VersionSchemeTestArgs(
                current_version="1-beta",
                increment=None,
                prerelease="beta",
                prerelease_offset=0,
                devrelease=None,
            ),
            "1.0.0-beta.1",
        ),
        (
            VersionSchemeTestArgs(
                current_version="1.0.0-alpha.1",
                increment=None,
                prerelease="alpha",
                prerelease_offset=0,
                devrelease=None,
            ),
            "1.0.0-alpha.2",
        ),
        (
            VersionSchemeTestArgs(
                current_version="1",
                increment=None,
                prerelease="rc",
                prerelease_offset=0,
                devrelease=None,
            ),
            "1.0.0-rc.0",
        ),
        (
            VersionSchemeTestArgs(
                current_version="1.0.0-rc.1+e20d7b57f3eb",
                increment="PATCH",
                prerelease=None,
                prerelease_offset=0,
                devrelease=None,
            ),
            "1.0.0",
        ),
        # simple_flow
        (
            VersionSchemeTestArgs(
                current_version="0.1.0",
                increment="PATCH",
                prerelease=None,
                prerelease_offset=0,
                devrelease=None,
            ),
            "0.1.1",
        ),
        (
            VersionSchemeTestArgs(
                current_version="0.1.0",
                increment="PATCH",
                prerelease=None,
                prerelease_offset=0,
                devrelease=1,
            ),
            "0.1.1-dev.1",
        ),
        (
            VersionSchemeTestArgs(
                current_version="0.1.1",
                increment="MINOR",
                prerelease=None,
                prerelease_offset=0,
                devrelease=None,
            ),
            "0.2.0",
        ),
        (
            VersionSchemeTestArgs(
                current_version="0.2.0",
                increment="MINOR",
                prerelease=None,
                prerelease_offset=0,
                devrelease=None,
            ),
            "0.3.0",
        ),
        (
            VersionSchemeTestArgs(
                current_version="0.2.0",
                increment="MINOR",
                prerelease=None,
                prerelease_offset=0,
                devrelease=1,
            ),
            "0.3.0-dev.1",
        ),
        (
            VersionSchemeTestArgs(
                current_version="0.3.0",
                increment="PATCH",
                prerelease=None,
                prerelease_offset=0,
                devrelease=None,
            ),
            "0.3.1",
        ),
        (
            VersionSchemeTestArgs(
                current_version="0.3.0",
                increment="PATCH",
                prerelease="alpha",
                prerelease_offset=0,
                devrelease=None,
            ),
            "0.3.1-alpha.0",
        ),
        (
            VersionSchemeTestArgs(
                current_version="0.3.1-alpha.0",
                increment=None,
                prerelease="alpha",
                prerelease_offset=0,
                devrelease=None,
            ),
            "0.3.1-alpha.1",
        ),
        (
            VersionSchemeTestArgs(
                current_version="0.3.0",
                increment="PATCH",
                prerelease="alpha",
                prerelease_offset=1,
                devrelease=None,
            ),
            "0.3.1-alpha.1",
        ),
        (
            VersionSchemeTestArgs(
                current_version="0.3.1-alpha.0",
                increment=None,
                prerelease="alpha",
                prerelease_offset=1,
                devrelease=None,
            ),
            "0.3.1-alpha.1",
        ),
        (
            VersionSchemeTestArgs(
                current_version="0.3.1-alpha.0",
                increment=None,
                prerelease=None,
                prerelease_offset=0,
                devrelease=None,
            ),
            "0.3.1",
        ),
        (
            VersionSchemeTestArgs(
                current_version="0.3.1",
                increment="PATCH",
                prerelease=None,
                prerelease_offset=0,
                devrelease=None,
            ),
            "0.3.2",
        ),
        (
            VersionSchemeTestArgs(
                current_version="0.4.2",
                increment="MAJOR",
                prerelease="alpha",
                prerelease_offset=0,
                devrelease=None,
            ),
            "1.0.0-alpha.0",
        ),
        (
            VersionSchemeTestArgs(
                current_version="1.0.0-alpha.0",
                increment=None,
                prerelease="alpha",
                prerelease_offset=0,
                devrelease=None,
            ),
            "1.0.0-alpha.1",
        ),
        (
            VersionSchemeTestArgs(
                current_version="1.0.0-alpha.1",
                increment=None,
                prerelease="alpha",
                prerelease_offset=0,
                devrelease=None,
            ),
            "1.0.0-alpha.2",
        ),
        (
            VersionSchemeTestArgs(
                current_version="1.0.0-alpha.1",
                increment=None,
                prerelease="alpha",
                prerelease_offset=0,
                devrelease=1,
            ),
            "1.0.0-alpha.2.dev.1",
        ),
        (
            VersionSchemeTestArgs(
                current_version="1.0.0-alpha.2.dev.0",
                increment=None,
                prerelease="alpha",
                prerelease_offset=0,
                devrelease=1,
            ),
            "1.0.0-alpha.3.dev.1",
        ),
        (
            VersionSchemeTestArgs(
                current_version="1.0.0-alpha.2.dev.0",
                increment=None,
                prerelease="alpha",
                prerelease_offset=0,
                devrelease=0,
            ),
            "1.0.0-alpha.3.dev.0",
        ),
        (
            VersionSchemeTestArgs(
                current_version="1.0.0-alpha.1",
                increment=None,
                prerelease="beta",
                prerelease_offset=0,
                devrelease=None,
            ),
            "1.0.0-beta.0",
        ),
        (
            VersionSchemeTestArgs(
                current_version="1.0.0-beta.0",
                increment=None,
                prerelease="beta",
                prerelease_offset=0,
                devrelease=None,
            ),
            "1.0.0-beta.1",
        ),
        (
            VersionSchemeTestArgs(
                current_version="1.0.0-beta.1",
                increment=None,
                prerelease="rc",
                prerelease_offset=0,
                devrelease=None,
            ),
            "1.0.0-rc.0",
        ),
        (
            VersionSchemeTestArgs(
                current_version="1.0.0-rc.0",
                increment=None,
                prerelease="rc",
                prerelease_offset=0,
                devrelease=None,
            ),
            "1.0.0-rc.1",
        ),
        (
            VersionSchemeTestArgs(
                current_version="1.0.0-rc.0",
                increment=None,
                prerelease="rc",
                prerelease_offset=0,
                devrelease=1,
            ),
            "1.0.0-rc.1.dev.1",
        ),
        (
            VersionSchemeTestArgs(
                current_version="1.0.0-rc.0",
                increment="PATCH",
                prerelease=None,
                prerelease_offset=0,
                devrelease=None,
            ),
            "1.0.0",
        ),
        (
            VersionSchemeTestArgs(
                current_version="1.0.0-alpha.3.dev.0",
                increment=None,
                prerelease="beta",
                prerelease_offset=0,
                devrelease=None,
            ),
            "1.0.0-beta.0",
        ),
        (
            VersionSchemeTestArgs(
                current_version="1.0.0",
                increment="PATCH",
                prerelease=None,
                prerelease_offset=0,
                devrelease=None,
            ),
            "1.0.1",
        ),
        (
            VersionSchemeTestArgs(
                current_version="1.0.1",
                increment="PATCH",
                prerelease=None,
                prerelease_offset=0,
                devrelease=None,
            ),
            "1.0.2",
        ),
        (
            VersionSchemeTestArgs(
                current_version="1.0.2",
                increment="MINOR",
                prerelease=None,
                prerelease_offset=0,
                devrelease=None,
            ),
            "1.1.0",
        ),
        (
            VersionSchemeTestArgs(
                current_version="1.1.0",
                increment="MINOR",
                prerelease=None,
                prerelease_offset=0,
                devrelease=None,
            ),
            "1.2.0",
        ),
        (
            VersionSchemeTestArgs(
                current_version="1.2.0",
                increment="PATCH",
                prerelease=None,
                prerelease_offset=0,
                devrelease=None,
            ),
            "1.2.1",
        ),
        (
            VersionSchemeTestArgs(
                current_version="1.2.1",
                increment="MAJOR",
                prerelease=None,
                prerelease_offset=0,
                devrelease=None,
            ),
            "2.0.0",
        ),
        # linear prerelease cases (never bump backwards on pre-releases)
        (
            VersionSchemeTestArgs(
                current_version="0.1.1-beta.1",
                increment=None,
                prerelease="alpha",
                prerelease_offset=0,
                devrelease=None,
            ),
            "0.1.1-beta.2",
        ),
        (
            VersionSchemeTestArgs(
                current_version="0.1.1-rc.0",
                increment=None,
                prerelease="alpha",
                prerelease_offset=0,
                devrelease=None,
            ),
            "0.1.1-rc.1",
        ),
        (
            VersionSchemeTestArgs(
                current_version="0.1.1-rc.0",
                increment=None,
                prerelease="beta",
                prerelease_offset=0,
                devrelease=None,
            ),
            "0.1.1-rc.1",
        ),
    ],
)
def test_bump_semver_version(
    version_args: VersionSchemeTestArgs, expected_version: str
):
    assert (
        str(
            SemVer2(version_args.current_version).bump(
                increment=version_args.increment,
                prerelease=version_args.prerelease,
                prerelease_offset=version_args.prerelease_offset,
                devrelease=version_args.devrelease,
            )
        )
        == expected_version
    )


@pytest.mark.parametrize(
    "version_args, expected_version",
    [
        (
            VersionSchemeTestArgs(
                current_version="4.5.0+0.1.0",
                increment="PATCH",
                prerelease=None,
                prerelease_offset=0,
                devrelease=None,
            ),
            "4.5.0+0.1.1",
        ),
        (
            VersionSchemeTestArgs(
                current_version="4.5.0+0.1.1",
                increment="MINOR",
                prerelease=None,
                prerelease_offset=0,
                devrelease=None,
            ),
            "4.5.0+0.2.0",
        ),
        (
            VersionSchemeTestArgs(
                current_version="4.5.0+0.2.0",
                increment="MAJOR",
                prerelease=None,
                prerelease_offset=0,
                devrelease=None,
            ),
            "4.5.0+1.0.0",
        ),
    ],
)
def test_bump_semver_version_local(
    version_args: VersionSchemeTestArgs, expected_version: str
):
    assert (
        str(
            SemVer2(version_args.current_version).bump(
                increment=version_args.increment,
                prerelease=version_args.prerelease,
                prerelease_offset=version_args.prerelease_offset,
                devrelease=version_args.devrelease,
                is_local_version=True,
            )
        )
        == expected_version
    )


def test_semver_scheme_property():
    version = SemVer2("0.0.1")
    assert version.scheme is SemVer2


def test_semver_implement_version_protocol():
    assert isinstance(SemVer2("0.0.1"), VersionProtocol)
