from pathlib import Path


def _repo_root() -> Path:
    return Path(__file__).resolve().parents[2]


def _script_text(name: str) -> str:
    return (_repo_root() / "scripts" / name).read_text(encoding="utf-8")


def _braced_body(text: str, declaration: str) -> str:
    start = text.index(declaration)
    brace_start = text.index("{", start)
    depth = 0

    for index, char in enumerate(text[brace_start:], start=brace_start):
        if char == "{":
            depth += 1
        elif char == "}":
            depth -= 1
            if depth == 0:
                return text[brace_start + 1 : index]

    raise AssertionError(f"Unclosed function body for {declaration}")


def test_install_sh_installs_claude_only_when_missing() -> None:
    text = _script_text("install.sh")
    body = _braced_body(text, "install_claude_if_missing()")
    main = text[text.index('parse_args "$@"') :]

    assert "Installs Claude Code if missing" in text
    assert "if command -v claude >/dev/null 2>&1; then" in body
    assert "Claude Code already found on PATH; skipping install." in body
    assert "require_command npm" in body
    assert "run npm install -g @anthropic-ai/claude-code" in body
    assert body.index("command -v claude") < body.index("run npm install")
    assert body.index("return 0") < body.index("run npm install")
    assert 'step "Installing Claude Code if missing"\ninstall_claude_if_missing' in main
    assert "npm install -g @anthropic-ai/claude-code" not in main


def test_install_sh_installs_missing_uv_without_self_update() -> None:
    text = _script_text("install.sh")
    body = _braced_body(text, "install_or_update_uv()")

    assert "if command -v uv >/dev/null 2>&1; then" in body
    assert "update_existing_uv" in body
    assert "run uv self update" not in body

    update_index = body.index("update_existing_uv")
    validate_existing_index = body.index("validate_uv_version", update_index)
    installer_index = body.index("run_uv_installer")
    validate_installed_index = body.index("validate_uv_version", installer_index)
    verification_index = body.index('if [ "$dry_run" -eq 0 ] && ! command -v uv')

    assert update_index < validate_existing_index < installer_index
    assert installer_index < verification_index < validate_installed_index


def test_install_sh_updates_uv_with_detected_source() -> None:
    text = _script_text("install.sh")
    update_body = _braced_body(text, "update_existing_uv()")

    assert "uv self update --dry-run" in text
    assert update_body.count("run uv self update") == 1
    assert update_body.index("uv_self_update_supported") < update_body.index(
        "run uv self update"
    )

    assert "brew list --versions uv" in text
    assert "run brew upgrade uv" in update_body
    assert "pipx list" in text
    assert "run pipx upgrade uv" in update_body
    assert "VIRTUAL_ENV" in text
    assert "run python -m pip install --upgrade uv" in update_body
    assert "uv_version_satisfies_minimum" in update_body
    assert "install source was not detected" in update_body


def test_install_sh_validates_minimum_uv_version() -> None:
    text = _script_text("install.sh")
    validate_body = _braced_body(text, "validate_uv_version()")

    assert 'MIN_UV_VERSION="0.11.0"' in text
    assert "uv self version --short" in text
    assert "version_ge" in validate_body
    assert "uv $MIN_UV_VERSION or newer is required" in validate_body


def test_install_ps1_installs_claude_only_when_missing() -> None:
    text = _script_text("install.ps1")
    body = _braced_body(text, "function Install-ClaudeIfMissing")

    assert "Installs Claude Code if missing" in text
    assert "if (Get-Command claude -ErrorAction SilentlyContinue)" in body
    assert "Claude Code already found on PATH; skipping install." in body
    assert 'Assert-CommandAvailable "npm"' in body
    assert (
        'Invoke-InstallCommand -FilePath "npm" '
        '-Arguments @("install", "-g", "@anthropic-ai/claude-code")'
    ) in body
    assert body.index("Get-Command claude") < body.index("Invoke-InstallCommand")
    assert body.index("return") < body.index("Invoke-InstallCommand")
    assert (
        'Write-Step "Installing Claude Code if missing"\nInstall-ClaudeIfMissing'
        in text
    )


def test_install_ps1_installs_missing_uv_without_self_update() -> None:
    text = _script_text("install.ps1")
    body = _braced_body(text, "function Install-OrUpdateUv")
    self_update = 'Invoke-InstallCommand -FilePath "uv" -Arguments @("self", "update")'

    assert "if (Get-Command uv -ErrorAction SilentlyContinue)" in body
    assert "Update-ExistingUv" in body
    assert self_update not in body

    update_index = body.index("Update-ExistingUv")
    validate_existing_index = body.index("Assert-MinUvVersion", update_index)
    installer_index = body.index("Invoke-UvInstaller")
    verification_index = body.index("if ((-not $DryRun)")
    validate_installed_index = body.index("Assert-MinUvVersion", installer_index)

    assert update_index < validate_existing_index < installer_index
    assert installer_index < verification_index < validate_installed_index


def test_install_ps1_updates_uv_with_detected_source() -> None:
    text = _script_text("install.ps1")
    update_body = _braced_body(text, "function Update-ExistingUv")
    self_update = 'Invoke-InstallCommand -FilePath "uv" -Arguments @("self", "update")'

    assert '"self", "update", "--dry-run"' in text
    assert update_body.count(self_update) == 1
    assert update_body.index("Test-UvSelfUpdateSupported") < update_body.index(
        self_update
    )

    assert (
        'Invoke-InstallCommand -FilePath "scoop" -Arguments @("update", "uv")'
        in update_body
    )
    assert '"winget"' in update_body
    assert '"astral-sh.uv"' in update_body
    assert '"--accept-package-agreements"' in update_body
    assert (
        'Invoke-InstallCommand -FilePath "pipx" -Arguments @("upgrade", "uv")'
        in update_body
    )
    assert (
        'Invoke-InstallCommand -FilePath "python" -Arguments @("-m", "pip", "install", "--upgrade", "uv")'
        in update_body
    )
    assert "Test-UvVersionSatisfiesMinimum" in update_body
    assert "install source was not detected" in update_body


def test_install_ps1_validates_minimum_uv_version() -> None:
    text = _script_text("install.ps1")
    validate_body = _braced_body(text, "function Assert-MinUvVersion")

    assert '$MinUvVersion = "0.11.0"' in text
    assert '"self", "version", "--short"' in text
    assert "[version]" in text
    assert "uv $MinUvVersion or newer is required" in validate_body
