"""Tests for project tag derivation (derive_project_tag)."""

from __future__ import annotations

from pathlib import Path
from unittest.mock import patch

from claude_engram.project import derive_project_tag


class TestDeriveProjectTag:
    """Tests for derive_project_tag() priority cascade."""

    def test_config_project_name_highest_priority(self) -> None:
        result = derive_project_tag(config_project_name="my-app")
        assert result == "proj:my-app"

    def test_config_project_name_strips_whitespace(self) -> None:
        result = derive_project_tag(config_project_name="  my-app  ")
        assert result == "proj:my-app"

    def test_config_project_name_empty_string_ignored(self) -> None:
        # Empty string should fall through to git/basename
        with patch("claude_engram.project._derive_from_git_remote", return_value=None):
            result = derive_project_tag(
                config_project_name="", project_dir=Path("/tmp/fallback-project")
            )
            assert result == "proj:fallback-project"

    def test_config_project_name_whitespace_only_ignored(self) -> None:
        with patch("claude_engram.project._derive_from_git_remote", return_value=None):
            result = derive_project_tag(
                config_project_name="   ", project_dir=Path("/tmp/some-project")
            )
            assert result == "proj:some-project"

    def test_git_remote_ssh_format(self) -> None:
        with patch("claude_engram.project.subprocess") as mock_sp:
            mock_sp.run.return_value = type(
                "Result",
                (),
                {"returncode": 0, "stdout": "git@github.com:my-org/my-repo.git\n"},
            )()
            mock_sp.TimeoutExpired = TimeoutError
            result = derive_project_tag(project_dir=Path("/tmp/repo"))
            assert result == "proj:my-org/my-repo"

    def test_git_remote_https_format(self) -> None:
        with patch("claude_engram.project.subprocess") as mock_sp:
            mock_sp.run.return_value = type(
                "Result",
                (),
                {
                    "returncode": 0,
                    "stdout": "https://github.com/org/repo.git\n",
                },
            )()
            mock_sp.TimeoutExpired = TimeoutError
            result = derive_project_tag(project_dir=Path("/tmp/repo"))
            assert result == "proj:org/repo"

    def test_git_remote_without_dot_git(self) -> None:
        with patch("claude_engram.project.subprocess") as mock_sp:
            mock_sp.run.return_value = type(
                "Result",
                (),
                {"returncode": 0, "stdout": "https://github.com/org/repo\n"},
            )()
            mock_sp.TimeoutExpired = TimeoutError
            result = derive_project_tag(project_dir=Path("/tmp/repo"))
            assert result == "proj:org/repo"

    def test_fallback_to_directory_basename(self) -> None:
        with patch("claude_engram.project._derive_from_git_remote", return_value=None):
            result = derive_project_tag(project_dir=Path("/home/user/my-project"))
            assert result == "proj:my-project"

    def test_proj_prefix_always_present(self) -> None:
        result = derive_project_tag(config_project_name="test")
        assert result is not None
        assert result.startswith("proj:")

    def test_git_not_available_falls_to_basename(self) -> None:
        with patch("claude_engram.project.subprocess") as mock_sp:
            mock_sp.run.return_value = type(
                "Result",
                (),
                {"returncode": 128, "stdout": ""},
            )()
            mock_sp.TimeoutExpired = TimeoutError
            result = derive_project_tag(project_dir=Path("/tmp/local-project"))
            assert result == "proj:local-project"

    def test_git_timeout_falls_to_basename(self) -> None:
        with patch("claude_engram.project.subprocess") as mock_sp:
            import subprocess

            mock_sp.run.side_effect = subprocess.TimeoutExpired("git", 2)
            mock_sp.TimeoutExpired = subprocess.TimeoutExpired
            result = derive_project_tag(project_dir=Path("/tmp/slow-project"))
            assert result == "proj:slow-project"

    def test_error_safety_returns_none(self) -> None:
        # Simulate an unexpected exception in the boundary
        with patch("claude_engram.project.Path") as mock_path:
            mock_path.cwd.side_effect = RuntimeError("unexpected")
            result = derive_project_tag()
            assert result is None

    def test_config_overrides_git(self) -> None:
        # Even if git would return something, config takes priority
        result = derive_project_tag(
            config_project_name="explicit-name", project_dir=Path("/tmp/repo")
        )
        assert result == "proj:explicit-name"
