"""Tests for qpip.project_config."""

from __future__ import annotations

import tempfile
import unittest
from pathlib import Path

from qpip.project_config import (
    ProjectConfigError,
    load_project_config,
    load_project_config_safe,
    update_project_config,
)


class LoadProjectConfigTests(unittest.TestCase):
    def test_loads_basic_tool_qpip_values(self) -> None:
        with tempfile.TemporaryDirectory() as tmp_dir:
            project_dir = Path(tmp_dir)
            (project_dir / "pyproject.toml").write_text(
                "[project]\nname = \"demo\"\nversion = \"0.1.0\"\n\n[tool.qpip]\nmirror = \"tsinghua\"\nvenv-dir = \".venv\"\n",
                encoding="utf-8",
            )

            config = load_project_config(project_dir)

            self.assertEqual(config.mirror, "tsinghua")
            self.assertEqual(config.venv_dirname, ".venv")
            self.assertEqual(config.source_path, (project_dir / "pyproject.toml").resolve())

    def test_ignores_tool_qpip_scripts_section_when_config_section_missing(self) -> None:
        with tempfile.TemporaryDirectory() as tmp_dir:
            project_dir = Path(tmp_dir)
            (project_dir / "pyproject.toml").write_text(
                "[project]\nname = \"demo\"\nversion = \"0.1.0\"\n\n[tool.qpip.scripts]\ntest = \"python -m unittest\"\n",
                encoding="utf-8",
            )

            config = load_project_config(project_dir)

            self.assertIsNone(config.mirror)
            self.assertIsNone(config.venv_dirname)

    def test_stops_at_next_table_for_stable_section_boundaries(self) -> None:
        with tempfile.TemporaryDirectory() as tmp_dir:
            project_dir = Path(tmp_dir)
            (project_dir / "pyproject.toml").write_text(
                "[tool.qpip]\nmirror = \"tsinghua\"\n\n[tool.qpip.scripts]\nvenv-dir = \"should-not-be-read\"\n",
                encoding="utf-8",
            )

            config = load_project_config(project_dir)

            self.assertEqual(config.mirror, "tsinghua")
            self.assertIsNone(config.venv_dirname)

    def test_supports_inline_comments_and_escaped_strings(self) -> None:
        with tempfile.TemporaryDirectory() as tmp_dir:
            project_dir = Path(tmp_dir)
            (project_dir / "pyproject.toml").write_text(
                "[tool.qpip]\nmirror = \"https://example.com/simple\\\"stable\" # keep comment\n",
                encoding="utf-8",
            )

            config = load_project_config(project_dir)

            self.assertEqual(config.mirror, 'https://example.com/simple"stable')

    def test_supports_table_header_with_trailing_comment(self) -> None:
        with tempfile.TemporaryDirectory() as tmp_dir:
            project_dir = Path(tmp_dir)
            (project_dir / "pyproject.toml").write_text(
                "[tool.qpip] # project defaults\nmirror = \"tsinghua\"\n",
                encoding="utf-8",
            )

            config = load_project_config(project_dir)

            self.assertEqual(config.mirror, "tsinghua")

    def test_supports_toml_unicode_escapes(self) -> None:
        with tempfile.TemporaryDirectory() as tmp_dir:
            project_dir = Path(tmp_dir)
            (project_dir / "pyproject.toml").write_text(
                "[tool.qpip]\nmirror = \"hello\\u4f60\\u597d\"\n",
                encoding="utf-8",
            )

            config = load_project_config(project_dir)

            self.assertEqual(config.mirror, "hello你好")

    def test_rejects_non_string_values(self) -> None:
        with tempfile.TemporaryDirectory() as tmp_dir:
            project_dir = Path(tmp_dir)
            (project_dir / "pyproject.toml").write_text(
                "[tool.qpip]\nmirror = [1, 2]\n",
                encoding="utf-8",
            )

            with self.assertRaises(ProjectConfigError):
                load_project_config(project_dir)

    def test_safe_loader_downgrades_invalid_lines_to_warning(self) -> None:
        with tempfile.TemporaryDirectory() as tmp_dir:
            project_dir = Path(tmp_dir)
            (project_dir / "pyproject.toml").write_text(
                "[tool.qpip]\nmirror \"missing-equals\"\n",
                encoding="utf-8",
            )

            result = load_project_config_safe(project_dir)

            self.assertIsNone(result.config.mirror)
            self.assertIsNotNone(result.warning)
            self.assertIn("无效行", result.warning or "")


class UpdateProjectConfigTests(unittest.TestCase):
    def test_rejects_rewrite_when_other_sections_are_invalid(self) -> None:
        with tempfile.TemporaryDirectory() as tmp_dir:
            project_dir = Path(tmp_dir)
            pyproject_path = project_dir / "pyproject.toml"
            original = (
                "[project]\n"
                "name = \"demo\"\n"
                "version = \"0.1.0\"\n"
                "authors = [\n"
                "  { name = \"Alice\", email = \"alice@example.com\" }\n"
                "\n"
                "[tool.qpip]\n"
                "mirror = \"tsinghua\"\n"
            )
            pyproject_path.write_text(original, encoding="utf-8")

            with self.assertRaises(ProjectConfigError):
                update_project_config(project_dir, mirror="aliyun")

            self.assertEqual(pyproject_path.read_text(encoding="utf-8"), original)


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