"""Tests for qpip.core."""

from __future__ import annotations

import unittest

from qpip.core import (
    DEFAULT_MIRROR,
    MIRRORS,
    build_pip_command,
    get_default_mirror,
    get_default_mirror_settings,
    normalize_pip_args,
    normalize_mirror_name,
    should_inject_mirror,
)
from qpip.project_config import ProjectConfig


class NormalizeMirrorNameTests(unittest.TestCase):
    def test_supports_aliases(self) -> None:
        self.assertEqual(normalize_mirror_name("aliyun"), "ali")
        self.assertEqual(normalize_mirror_name("TUNA"), "tsinghua")
        self.assertEqual(normalize_mirror_name("pip"), "pypi")

    def test_rejects_unknown_mirror(self) -> None:
        with self.assertRaises(ValueError):
            normalize_mirror_name("unknown")


class GetDefaultMirrorTests(unittest.TestCase):
    def test_invalid_environment_value_falls_back(self) -> None:
        mirror, warning = get_default_mirror({"QPIP_DEFAULT_MIRROR": "bad"})

        self.assertEqual(mirror, DEFAULT_MIRROR)
        self.assertIn("已回退到", warning)

    def test_project_config_provides_default_mirror(self) -> None:
        mirror, warning, source = get_default_mirror_settings(
            env={},
            project_config=ProjectConfig(mirror="tsinghua"),
        )

        self.assertEqual(mirror, "tsinghua")
        self.assertIsNone(warning)
        self.assertEqual(source, "project")


class MirrorInjectionTests(unittest.TestCase):
    def test_install_alias_is_expanded(self) -> None:
        command = build_pip_command(["i", "requests"], mirror="ali", python_executable="python")

        self.assertEqual(
            command,
            ["python", "-m", "pip", "install", "requests", "-i", MIRRORS["ali"]],
        )

    def test_update_alias_is_expanded_to_upgrade_install(self) -> None:
        command = build_pip_command(["update", "requests"], mirror="ali", python_executable="python")

        self.assertEqual(
            command,
            ["python", "-m", "pip", "install", "--upgrade", "requests", "-i", MIRRORS["ali"]],
        )

    def test_up_alias_is_expanded_to_upgrade_install(self) -> None:
        command = build_pip_command(["up", "requests"], mirror="ali", python_executable="python")

        self.assertEqual(
            command,
            ["python", "-m", "pip", "install", "--upgrade", "requests", "-i", MIRRORS["ali"]],
        )

    def test_un_alias_is_expanded_to_uninstall(self) -> None:
        command = build_pip_command(["un", "requests"], mirror="ali", python_executable="python")

        self.assertEqual(
            command,
            ["python", "-m", "pip", "uninstall", "requests"],
        )

    def test_install_injects_index_url(self) -> None:
        command = build_pip_command(["install", "requests"], mirror="ali", python_executable="python")

        self.assertEqual(
            command,
            ["python", "-m", "pip", "install", "requests", "-i", MIRRORS["ali"]],
        )

    def test_official_pypi_mirror_can_be_selected_by_pip_alias(self) -> None:
        command = build_pip_command(["install", "numpy"], mirror="pip", python_executable="python")

        self.assertEqual(
            command,
            ["python", "-m", "pip", "install", "numpy", "-i", MIRRORS["pypi"]],
        )

    def test_explicit_index_url_disables_injection(self) -> None:
        command = build_pip_command(
            ["install", "requests", "--index-url", "https://example.com/simple"],
            mirror="ali",
            python_executable="python",
        )

        self.assertEqual(
            command,
            [
                "python",
                "-m",
                "pip",
                "install",
                "requests",
                "--index-url",
                "https://example.com/simple",
            ],
        )

    def test_non_network_commands_do_not_inject_index_url(self) -> None:
        self.assertFalse(should_inject_mirror(["list"]))
        self.assertFalse(should_inject_mirror(["config", "list"]))
        self.assertFalse(should_inject_mirror(["uninstall", "requests"]))
        self.assertFalse(should_inject_mirror(["un", "requests"]))

    def test_update_is_treated_as_network_command(self) -> None:
        self.assertTrue(should_inject_mirror(["update", "requests"]))
        self.assertTrue(should_inject_mirror(["up", "requests"]))

    def test_normalize_pip_args_preserves_options_before_alias(self) -> None:
        self.assertEqual(
            normalize_pip_args(["-v", "i", "requests"]),
            ["-v", "install", "requests"],
        )

    def test_normalize_pip_args_expands_update_alias(self) -> None:
        self.assertEqual(
            normalize_pip_args(["-v", "update", "requests"]),
            ["-v", "install", "--upgrade", "requests"],
        )

    def test_normalize_pip_args_expands_uninstall_alias(self) -> None:
        self.assertEqual(
            normalize_pip_args(["-y", "un", "requests"]),
            ["-y", "uninstall", "requests"],
        )

    def test_update_requires_target(self) -> None:
        with self.assertRaises(ValueError):
            build_pip_command(["update"], mirror="ali")

    def test_empty_args_raise(self) -> None:
        with self.assertRaises(ValueError):
            build_pip_command([], mirror="ali")


if __name__ == "__main__":
    unittest.main()
