"""Contains all unit tests for build utils."""

import os
from collections.abc import Callable
from typing import Any
from unittest.mock import patch

import pytest

from voraus_pipeline_utils.constants import (
    ENV_VAR_DOCKER_REGISTRY,
    ENV_VAR_DOCKER_TAGS,
    ENV_VAR_IMAGE_NAME,
    ENV_VAR_REPOSITORIES,
)
from voraus_pipeline_utils.methods.environment import (
    _get_env_or_none,
    get_branch_name,
    get_build_number,
    get_change_target_branch_name,
    get_docker_image_name_from_env,
    get_docker_registry_from_env,
    get_docker_repositories_from_env,
    get_docker_tags_from_env,
    get_git_tag,
    is_ci,
    is_github,
    is_jenkins,
)


@patch.dict(os.environ, clear=True)
def test___get_env_or_none_empty() -> None:
    assert _get_env_or_none(env_var="DOES_NOT_EXIST") is None


@patch.dict(os.environ, {"KEY": "VALUE"})
def test___get_env_or_none_without_decode() -> None:
    assert _get_env_or_none(env_var="KEY") == "VALUE"


@patch.dict(os.environ, {"KEY": "1"})
def test___get_env_or_none_with_decode() -> None:
    assert _get_env_or_none(env_var="KEY", decode=int) == 1


@patch.dict(os.environ, {"KEY": "VALUE"})
def test___get_env_or_none_with_decode_error() -> None:
    with pytest.raises(ValueError, match="invalid literal for int"):
        assert _get_env_or_none(env_var="KEY", decode=int)


@pytest.mark.parametrize(
    ("env", "expected_result", "expected_log"),
    [
        (
            {"KEY1": "VALUE1", "KEY2": "VALUE2"},
            "VALUE1",
            "Multiple environment variables from ('KEY1', 'KEY2') are set: ['VALUE1', 'VALUE2']. Using the first one.",
        ),
        ({"KEY1": "VALUE1", "KEY2": ""}, "VALUE1", None),
        ({"KEY1": "", "KEY2": "VALUE2"}, "VALUE2", None),
    ],
)
def test___get_env_or_none_multiple_keys(
    env: dict, expected_result: str | None, expected_log: str | None, caplog: pytest.LogCaptureFixture
) -> None:
    with patch.dict(os.environ, env), caplog.at_level("WARNING"):
        assert _get_env_or_none(env_var=("KEY1", "KEY2")) == expected_result

        if expected_log:
            assert expected_log in caplog.messages


@patch.dict(os.environ, {"JENKINS_URL": "http://jenkins.example.com"})
def test_is_jenkins() -> None:
    assert is_jenkins() is True


@patch.dict(os.environ, {"GITHUB_ACTIONS": "true"})
def test_is_github() -> None:
    assert is_github() is True


@patch.dict(os.environ, clear=True)
def test_is_not_jenkins() -> None:
    assert is_jenkins() is False


@patch.dict(os.environ, clear=True)
def test_is_not_github() -> None:
    assert is_github() is False


@patch.dict(os.environ, {"CI": "true"})
def test_is_ci() -> None:
    assert is_ci() is True


@patch.dict(os.environ, clear=True)
def test_is_not_ci() -> None:
    assert is_ci() is False


@pytest.mark.parametrize(
    ("function", "environment_dict", "expected_result"),
    [
        # Jenkins
        (get_git_tag, {"TAG_NAME": "TEST"}, "TEST"),
        (get_branch_name, {"BRANCH_NAME": "TEST"}, "TEST"),
        (get_build_number, {"BUILD_NUMBER": "42"}, 42),
        (get_change_target_branch_name, {"CHANGE_TARGET": "main"}, "main"),
        # GitHub Actions
        (
            get_git_tag,
            {
                "GITHUB_ACTIONS": "true",
                "GITHUB_REF_TYPE": "tag",
                "GITHUB_REF_NAME": "MockedTag",
            },
            "MockedTag",
        ),
        (get_branch_name, {"GITHUB_REF_NAME": "github-branch-name"}, "github-branch-name"),
        (get_build_number, {"GITHUB_RUN_NUMBER": "43"}, 43),
        (get_change_target_branch_name, {"GITHUB_BASE_REF": "main"}, "main"),
        # VPU variables
        (get_docker_image_name_from_env, {ENV_VAR_IMAGE_NAME: "example-image-name"}, "example-image-name"),
        (get_docker_repositories_from_env, {ENV_VAR_REPOSITORIES: "rep1"}, ["rep1"]),
        (get_docker_repositories_from_env, {ENV_VAR_REPOSITORIES: "rep1,rep2"}, ["rep1", "rep2"]),
        (get_docker_tags_from_env, {ENV_VAR_DOCKER_TAGS: "tag1"}, ["tag1"]),
        (get_docker_tags_from_env, {ENV_VAR_DOCKER_TAGS: "tag1,tag2"}, ["tag1", "tag2"]),
    ],
)
def test_get_environment_variables(function: Callable, environment_dict: dict, expected_result: Any) -> None:
    with patch.dict(os.environ, environment_dict):
        assert function() == expected_result

    # Test without value
    with patch.dict(os.environ, clear=True):
        assert function() is None


def test_get_docker_registry_from_env() -> None:
    with patch.dict(os.environ, {ENV_VAR_DOCKER_REGISTRY: "example.com"}):
        assert get_docker_registry_from_env() == "example.com"
    with (
        patch.dict(os.environ, clear=True),
        pytest.raises(
            ValueError, match="Unable to determine docker registry from environment variable VPU_DOCKER_REGISTRY"
        ),
    ):
        get_docker_registry_from_env()
