"""Tests for CLI installer, especially Windows compatibility."""

from __future__ import annotations

import os
from pathlib import Path
from unittest.mock import patch, MagicMock

import pytest

from aleph.cli import _find_claude_cli, is_client_installed, CLIENTS


class TestFindClaudeCli:
    """Tests for _find_claude_cli() Windows compatibility (issue #17)."""

    def test_find_claude_standard_unix(self) -> None:
        """Test finding 'claude' on Unix-like systems."""
        with patch("shutil.which") as mock_which:
            mock_which.return_value = "/usr/local/bin/claude"
            result = _find_claude_cli()
            assert result == "claude"
            mock_which.assert_called_once_with("claude")

    def test_find_claude_not_found(self) -> None:
        """Test when claude is not found anywhere."""
        with patch("shutil.which", return_value=None):
            with patch("platform.system", return_value="Linux"):
                result = _find_claude_cli()
                assert result is None

    def test_find_claude_windows_cmd(self) -> None:
        """Test finding claude.cmd on Windows (NPM installation)."""
        def mock_which(name: str) -> str | None:
            if name == "claude.cmd":
                return "C:\\Users\\test\\AppData\\Roaming\\npm\\claude.cmd"
            return None

        with patch("shutil.which", side_effect=mock_which):
            with patch("platform.system", return_value="Windows"):
                result = _find_claude_cli()
                assert result == "claude.cmd"

    def test_find_claude_windows_ps1(self) -> None:
        """Test finding claude.ps1 on Windows."""
        def mock_which(name: str) -> str | None:
            if name == "claude.ps1":
                return "C:\\Users\\test\\AppData\\Roaming\\npm\\claude.ps1"
            return None

        with patch("shutil.which", side_effect=mock_which):
            with patch("platform.system", return_value="Windows"):
                result = _find_claude_cli()
                assert result == "claude.ps1"

    def test_find_claude_windows_exe(self) -> None:
        """Test finding claude.exe on Windows."""
        def mock_which(name: str) -> str | None:
            if name == "claude.exe":
                return "C:\\Program Files\\Claude\\claude.exe"
            return None

        with patch("shutil.which", side_effect=mock_which):
            with patch("platform.system", return_value="Windows"):
                result = _find_claude_cli()
                assert result == "claude.exe"

    def test_find_claude_windows_npm_appdata_fallback(self) -> None:
        """Test fallback to npm APPDATA path when shutil.which fails."""
        with patch("shutil.which", return_value=None):
            with patch("platform.system", return_value="Windows"):
                with patch.dict(os.environ, {"APPDATA": "C:\\Users\\test\\AppData\\Roaming"}):
                    npm_path = Path("C:\\Users\\test\\AppData\\Roaming\\npm\\claude.cmd")
                    with patch.object(Path, "exists", return_value=True):
                        result = _find_claude_cli()
                        # Should return the full path from npm
                        assert result is not None
                        assert "npm" in result
                        assert "claude.cmd" in result or "claude.ps1" in result

    def test_find_claude_prefers_standard_name(self) -> None:
        """Test that 'claude' is preferred over Windows extensions."""
        def mock_which(name: str) -> str | None:
            # Both exist, but 'claude' should be preferred
            if name == "claude":
                return "/usr/local/bin/claude"
            if name == "claude.cmd":
                return "C:\\somewhere\\claude.cmd"
            return None

        with patch("shutil.which", side_effect=mock_which):
            result = _find_claude_cli()
            assert result == "claude"


class TestIsClientInstalled:
    """Tests for is_client_installed() with Claude Code client."""

    def test_claude_code_installed(self) -> None:
        """Test detection when Claude Code CLI is available."""
        with patch("aleph.cli._find_claude_cli", return_value="claude"):
            client = CLIENTS["claude-code"]
            assert is_client_installed(client) is True

    def test_claude_code_not_installed(self) -> None:
        """Test detection when Claude Code CLI is not available."""
        with patch("aleph.cli._find_claude_cli", return_value=None):
            client = CLIENTS["claude-code"]
            assert is_client_installed(client) is False

    def test_claude_code_windows_cmd_installed(self) -> None:
        """Test detection when Claude Code is installed as .cmd on Windows."""
        with patch("aleph.cli._find_claude_cli", return_value="claude.cmd"):
            client = CLIENTS["claude-code"]
            assert is_client_installed(client) is True
