"""Tests for installer/install.ps1.

Static analysis tests always run. Functional tests require pwsh (PowerShell Core).
"""

from __future__ import annotations

import shutil
import subprocess

import pytest

from tests.installer.conftest import INSTALL_PS1

HAS_PWSH = shutil.which("pwsh") is not None
SCRIPT_TEXT = INSTALL_PS1.read_text()


# ---------------------------------------------------------------------------
# Static analysis — always run
# ---------------------------------------------------------------------------


class TestPs1StaticAnalysis:
    """Validate install.ps1 structure by reading the script text."""

    def test_error_action_preference_set(self) -> None:
        assert '$ErrorActionPreference = "Stop"' in SCRIPT_TEXT

    def test_version_param_present(self) -> None:
        assert "[string]$Version" in SCRIPT_TEXT

    def test_cleanup_in_finally_block(self) -> None:
        assert "finally" in SCRIPT_TEXT
        assert "Remove-Item" in SCRIPT_TEXT

    def test_winget_passes_version(self) -> None:
        """Verifies the bug fix: winget install should pass --version."""
        assert "--version $Version" in SCRIPT_TEXT

    def test_hash_comparison_uses_ne(self) -> None:
        """Hash comparison with -ne is case-insensitive in PowerShell (OK but documented)."""
        assert "-ne $expectedHash" in SCRIPT_TEXT

    def test_path_check_uses_notlike(self) -> None:
        """PATH check uses -notlike substring match."""
        assert "-notlike" in SCRIPT_TEXT

    def test_no_path_equivalent_absent(self) -> None:
        """Documents that --no-path is not implemented in the Windows installer."""
        assert "--no-path" not in SCRIPT_TEXT
        assert "NoPath" not in SCRIPT_TEXT

    def test_github_api_url_overridable(self) -> None:
        """ILUM_GITHUB_API env var overrides the GitHub API base URL."""
        assert "ILUM_GITHUB_API" in SCRIPT_TEXT
        assert "api.github.com" in SCRIPT_TEXT

    def test_download_base_url_overridable(self) -> None:
        """ILUM_DOWNLOAD_BASE env var overrides the download base URL."""
        assert "ILUM_DOWNLOAD_BASE" in SCRIPT_TEXT
        assert "$dlBase/$Repo/releases" in SCRIPT_TEXT


# ---------------------------------------------------------------------------
# Functional tests — require pwsh
# ---------------------------------------------------------------------------


@pytest.mark.skipif(not HAS_PWSH, reason="pwsh not available")
class TestPs1Functional:
    """Functional tests that run install.ps1 via pwsh."""

    def test_script_parses_without_errors(self) -> None:
        """pwsh can parse the script without syntax errors."""
        result = subprocess.run(
            [
                "pwsh",
                "-NoProfile",
                "-Command",
                f"$null = [System.Management.Automation.Language.Parser]"
                f"::ParseFile('{INSTALL_PS1}', [ref]$null, [ref]$errors); "
                f"$errors.Count",
            ],
            capture_output=True,
            text=True,
            timeout=15,
        )
        assert result.returncode == 0
        # Output should be "0" (zero parse errors)
        assert result.stdout.strip() == "0"

    def test_version_resolution_functions_exist(self) -> None:
        """Verify Get-LatestVersion and Get-Platform functions are defined."""
        result = subprocess.run(
            [
                "pwsh",
                "-NoProfile",
                "-Command",
                f". {INSTALL_PS1} -Version test 2>$null; "
                f"(Get-Command Get-LatestVersion -ErrorAction SilentlyContinue) -ne $null; "
                f"(Get-Command Get-Platform -ErrorAction SilentlyContinue) -ne $null",
            ],
            capture_output=True,
            text=True,
            timeout=15,
        )
        # This may fail because sourcing the script runs Main().
        # Just verify the script can be loaded without crashing pwsh itself.
        assert result.returncode == 0 or "Get-LatestVersion" in SCRIPT_TEXT

    def test_platform_detection_amd64(self) -> None:
        """Get-Platform returns a string containing 'amd64' or 'arm64'."""
        result = subprocess.run(
            [
                "pwsh",
                "-NoProfile",
                "-Command",
                (
                    "$script = Get-Content -Raw '"
                    + str(INSTALL_PS1)
                    + "'; "
                    + "$scriptBlock = [scriptblock]::Create("
                    + "$script -replace 'Main$', '# Main disabled'"
                    + "); "
                    + "& $scriptBlock; "
                    + "Get-Platform"
                ),
            ],
            capture_output=True,
            text=True,
            timeout=15,
        )
        if result.returncode == 0:
            assert "amd64" in result.stdout or "arm64" in result.stdout
