"""Graphical sudo prompts: command rewriting and helper resolution.
Pure logic — no display, no sudo, no password."""

import sys
from pathlib import Path

import pytest

sys.path.insert(0, str(Path(__file__).resolve().parent.parent))

from bolt_pet import sudo_askpass


# ── rewriting ────────────────────────────────────────────────────────────────


@pytest.mark.parametrize(
    "command,expected",
    [
        ("sudo apt update", "sudo -A apt update"),
        ("sudo  apt update", "sudo -A  apt update"),  # spacing preserved
        ("apt update && sudo apt upgrade", "apt update && sudo -A apt upgrade"),
        ("ls; sudo reboot", "ls; sudo -A reboot"),
        ("echo hi | sudo tee /etc/motd", "echo hi | sudo -A tee /etc/motd"),
        ("sudo systemctl restart x\nsudo systemctl status x",
         "sudo -A systemctl restart x\nsudo -A systemctl status x"),
    ],
)
def test_bare_sudo_gets_the_askpass_flag(command, expected):
    assert sudo_askpass.add_askpass_flag(command) == expected


@pytest.mark.parametrize(
    "command",
    [
        "sudo -n apt update",     # explicitly non-interactive
        "sudo -A apt update",     # already asking
        "sudo -u bob whoami",     # the caller was explicit
        "ls -la",                 # no sudo at all
        "echo 'run sudo later'",  # inside a quoted string
        "pseudo --version",       # not the word sudo
    ],
)
def test_commands_that_must_not_be_rewritten(command):
    assert sudo_askpass.add_askpass_flag(command) == command


def test_blank_input():
    assert sudo_askpass.add_askpass_flag("") == ""
    assert sudo_askpass.add_askpass_flag(None) == ""


@pytest.mark.parametrize(
    "command,expected",
    [
        ("sudo apt update", True),
        ("ls && sudo reboot", True),
        ("ls -la", False),
        ("echo 'sudo'", False),
        ("", False),
    ],
)
def test_which_commands_get_the_longer_timeout(command, expected):
    assert sudo_askpass.needs_password_prompt(command) is expected


# ── helper resolution ────────────────────────────────────────────────────────


def test_a_configured_helper_wins():
    found = sudo_askpass.find_helper(
        configured="/opt/my-askpass", is_executable=lambda p: p == "/opt/my-askpass",
    )
    assert found == "/opt/my-askpass"


def test_a_configured_helper_that_is_not_executable_is_not_silently_replaced():
    """Better to have sudo fail than to quietly prompt with something the
    user didn't choose."""
    assert sudo_askpass.find_helper(
        configured="/opt/typo", is_executable=lambda p: False, which=lambda t: "/usr/bin/zenity",
    ) is None


def test_a_real_askpass_binary_beats_a_generated_wrapper():
    found = sudo_askpass.find_helper(
        configured="", is_executable=lambda p: p == "/usr/bin/ksshaskpass",
        which=lambda tool: "/usr/bin/zenity",
    )
    assert found == "/usr/bin/ksshaskpass"


def test_falls_back_to_wrapping_a_dialog_tool(tmp_path):
    found = sudo_askpass.find_helper(
        configured="", is_executable=lambda p: False,
        which=lambda tool: "/usr/bin/zenity" if tool == "zenity" else None,
        cache_dir=tmp_path,
    )
    script = tmp_path / "askpass.sh"
    assert found == str(script)
    assert "zenity --password" in script.read_text()
    assert script.stat().st_mode & 0o777 == 0o700  # nobody else edits the password box


def test_no_helper_available_at_all():
    assert sudo_askpass.find_helper(
        configured="", is_executable=lambda p: False, which=lambda tool: None,
    ) is None


def test_the_wrapper_passes_sudos_prompt_through():
    """sudo hands the helper its prompt as $1 — it names the account the
    password is for, which is worth showing in the dialog."""
    script = sudo_askpass.helper_script("/usr/bin/zenity")
    assert script.startswith("#!/bin/sh")
    assert '"$1"' in script


def test_environment_points_sudo_at_the_helper():
    env = sudo_askpass.environment("/tmp/askpass.sh", base={"PATH": "/usr/bin"})
    assert env["SUDO_ASKPASS"] == "/tmp/askpass.sh"
    assert env["PATH"] == "/usr/bin"  # the rest of the environment survives
