# Copyright 2016-2024, Pulumi Corporation.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import os
import subprocess
import tempfile
import unittest
from pathlib import Path

import pytest
from semver import VersionInfo

from pulumi.automation import InvalidVersionError, PulumiCommand
from pulumi.automation._cmd import _fixup_path, _parse_and_validate_pulumi_version


def test_install_default_root():
    requested_version = VersionInfo.parse("3.101.0")

    p = PulumiCommand.install(version=requested_version)

    pulumiBin = (
        Path.home() / ".pulumi" / "versions" / str(requested_version) / "bin" / "pulumi"
    )
    try:
        pulumiBin.stat()
    except Exception as exception:
        pytest.fail(f"did not find pulumi binary: {exception}")
    assert p.version == "3.101.0"
    out = subprocess.check_output([pulumiBin, "version"])
    assert out.decode("utf-8").strip() == "v" + str(requested_version)


def test_install_twice():
    with tempfile.TemporaryDirectory(prefix="automation-test-") as root:
        requested_version = VersionInfo.parse("3.101.0")
        pulumiBin = Path(root) / "bin" / "pulumi"

        PulumiCommand.install(version=requested_version, root=root)
        stat1 = pulumiBin.stat()

        PulumiCommand.install(version=requested_version, root=root)
        stat2 = pulumiBin.stat()

        assert stat1.st_ino == stat2.st_ino


def test_incompatible_version():
    with tempfile.TemporaryDirectory(prefix="automation-test-") as root:
        installed_version = VersionInfo.parse("3.99.0")
        PulumiCommand.install(version=installed_version, root=root)
        requested_version = VersionInfo.parse("3.101.0")
        # Try getting an incompatible version
        try:
            PulumiCommand(root=root, version=requested_version)
            pytest.fail("expected an exception")
        except InvalidVersionError as exception:
            assert "Minimum version requirement failed" in str(exception)
        # Succeeds when disabling version check
        PulumiCommand(root=root, version=requested_version, skip_version_check=True)


def test_fixup_env():
    env = {"PATH": "/usr/bin", "SOME_VAR": "some value"}
    new_env = _fixup_path(env, "/tmp/pulumi-install/bin")
    if os.name == "nt":
        assert new_env["PATH"] == "/tmp/pulumi-install/bin;/usr/bin"
    else:
        assert new_env["PATH"] == "/tmp/pulumi-install/bin:/usr/bin"


MAJOR = "Major version mismatch."
MINIMAL = "Minimum version requirement failed."
PARSE = "Could not parse the Pulumi CLI"
version_tests = [
    # current_version, expected_error regex, opt_out
    ("100.0.0", MAJOR, False),
    ("1.0.0", MINIMAL, False),
    ("2.22.0", None, False),
    ("2.1.0", MINIMAL, False),
    ("2.21.2", None, False),
    ("2.21.1", None, False),
    ("2.21.0", MINIMAL, False),
    # Note that prerelease < release so this case will error
    ("2.21.1-alpha.1234", MINIMAL, False),
    # Test opting out of version check
    ("2.20.0", None, True),
    ("2.22.0", None, True),
    # Test invalid version
    ("invalid", PARSE, False),
    ("invalid", None, True),
]
test_min_version = VersionInfo.parse("2.21.1")


class TestParseAndValidatePulumiVersion(unittest.TestCase):
    def test_validate_pulumi_version(self):
        for current_version, expected_error, opt_out in version_tests:
            with self.subTest():
                if expected_error:
                    with self.assertRaisesRegex(
                        InvalidVersionError,
                        expected_error,
                        msg=f"min_version:{test_min_version}, current_version:{current_version}",
                    ):
                        _parse_and_validate_pulumi_version(
                            test_min_version, current_version, opt_out
                        )
                else:
                    _parse_and_validate_pulumi_version(
                        test_min_version, current_version, opt_out
                    )