"""Tests for Homebrew wrapper module."""

from __future__ import annotations

import tempfile
from datetime import datetime
from pathlib import Path
from unittest.mock import MagicMock, patch

import pytest
from typer.testing import CliRunner

from gaol.brew import (
    BrewConfig,
    BrewContainer,
    BrewContainerError,
    BrewError,
    BrewInstallError,
    BrewPackageNotFoundError,
    InstalledPackage,
    WrapperExistsError,
    WrapperInstaller,
    WrapperNotFoundError,
)


class TestBrewModels:
    """Tests for brew Pydantic models."""

    def test_installed_package_creation(self) -> None:
        """Test creating a basic installed package."""
        entry = InstalledPackage(
            package_name="ffmpeg",
            wrapper_path="/home/user/.local/bin/ffmpeg",
            binaries=["ffmpeg", "ffprobe"],
        )
        assert entry.package_name == "ffmpeg"
        assert entry.container_name == "homebrew"
        assert entry.wrapper_path == "/home/user/.local/bin/ffmpeg"
        assert "ffmpeg" in entry.binaries
        assert "ffprobe" in entry.binaries
        assert entry.version is None

    def test_installed_package_with_all_fields(self) -> None:
        """Test installed package with all optional fields."""
        entry = InstalledPackage(
            package_name="ripgrep",
            container_name="custom-brew",
            wrapper_path="/custom/bin/rg",
            binaries=["rg"],
            installed_at=datetime(2024, 1, 15, 10, 30),
            version="14.0.0",
        )
        assert entry.container_name == "custom-brew"
        assert entry.version == "14.0.0"
        assert entry.installed_at.year == 2024

    def test_brew_config_defaults(self) -> None:
        """Test default configuration values."""
        config = BrewConfig()
        assert config.container_name == "homebrew"
        assert config.wrapper_dir is None
        assert config.mount_home is True
        assert config.runtime == "docker"
        assert config.distro == "bookworm"

    def test_brew_config_custom(self) -> None:
        """Test custom configuration values."""
        config = BrewConfig(
            container_name="my-brew",
            wrapper_dir="/custom/bin",
            mount_home=False,
            runtime="podman",
            distro="noble",
        )
        assert config.container_name == "my-brew"
        assert config.wrapper_dir == "/custom/bin"
        assert config.mount_home is False
        assert config.runtime == "podman"
        assert config.distro == "noble"


class TestBrewExceptions:
    """Tests for brew exception classes."""

    def test_brew_error_is_base(self) -> None:
        """Test BrewError is the base exception."""
        error = BrewError("test error")
        assert str(error) == "test error"
        assert isinstance(error, Exception)

    def test_brew_container_error(self) -> None:
        """Test BrewContainerError."""
        error = BrewContainerError("container failed")
        assert str(error) == "container failed"
        assert isinstance(error, BrewError)

    def test_brew_install_error(self) -> None:
        """Test BrewInstallError with package info."""
        error = BrewInstallError("ffmpeg", "network timeout")
        assert error.package == "ffmpeg"
        assert "ffmpeg" in str(error)
        assert "network timeout" in str(error)
        assert isinstance(error, BrewError)

    def test_brew_package_not_found_error(self) -> None:
        """Test BrewPackageNotFoundError."""
        error = BrewPackageNotFoundError("nonexistent-pkg")
        assert error.package == "nonexistent-pkg"
        assert "nonexistent-pkg" in str(error)
        assert "not found" in str(error)

    def test_wrapper_exists_error(self) -> None:
        """Test WrapperExistsError with binary and path."""
        error = WrapperExistsError("ffmpeg", "/usr/bin/ffmpeg")
        assert error.binary == "ffmpeg"
        assert error.path == "/usr/bin/ffmpeg"
        assert "ffmpeg" in str(error)
        assert "/usr/bin/ffmpeg" in str(error)

    def test_wrapper_not_found_error(self) -> None:
        """Test WrapperNotFoundError."""
        error = WrapperNotFoundError("ripgrep")
        assert error.package == "ripgrep"
        assert "ripgrep" in str(error)


class TestWrapperInstaller:
    """Tests for wrapper script installation."""

    def test_get_wrapper_dir_default(self, tmp_path: Path) -> None:
        """Test default wrapper directory."""
        with patch.object(Path, "home", return_value=tmp_path):
            installer = WrapperInstaller()
            wrapper_dir = installer.get_wrapper_dir()
            assert wrapper_dir == tmp_path / ".local" / "bin"

    def test_get_wrapper_dir_custom(self, tmp_path: Path) -> None:
        """Test custom wrapper directory from config."""
        config = BrewConfig(wrapper_dir=str(tmp_path / "custom" / "bin"))
        installer = WrapperInstaller(config=config)
        wrapper_dir = installer.get_wrapper_dir()
        assert wrapper_dir == tmp_path / "custom" / "bin"

    def test_install_creates_wrapper_script(self, tmp_path: Path) -> None:
        """Test that install creates wrapper scripts."""
        wrapper_dir = tmp_path / "bin"
        config = BrewConfig(wrapper_dir=str(wrapper_dir))

        with patch("gaol.brew.wrapper.get_data_dir", return_value=tmp_path):
            installer = WrapperInstaller(config=config)
            installed = installer.install("ffmpeg", ["ffmpeg", "ffprobe"])

        assert len(installed) == 2

        # Check wrapper scripts exist
        ffmpeg_wrapper = wrapper_dir / "ffmpeg"
        ffprobe_wrapper = wrapper_dir / "ffprobe"
        assert ffmpeg_wrapper.exists()
        assert ffprobe_wrapper.exists()

        # Check wrapper content
        content = ffmpeg_wrapper.read_text()
        assert "#!/bin/bash" in content
        assert "gaol brew run ffmpeg" in content
        assert "exec" in content

    def test_install_makes_wrapper_executable(self, tmp_path: Path) -> None:
        """Test that wrappers have executable permission."""
        wrapper_dir = tmp_path / "bin"
        config = BrewConfig(wrapper_dir=str(wrapper_dir))

        with patch("gaol.brew.wrapper.get_data_dir", return_value=tmp_path):
            installer = WrapperInstaller(config=config)
            installer.install("cowsay", ["cowsay"])

        wrapper = wrapper_dir / "cowsay"
        # Check executable bit (owner executable)
        assert wrapper.stat().st_mode & 0o100

    def test_install_raises_if_wrapper_exists_not_ours(self, tmp_path: Path) -> None:
        """Test that install fails if wrapper exists and is not ours."""
        wrapper_dir = tmp_path / "bin"
        wrapper_dir.mkdir(parents=True)
        existing = wrapper_dir / "ffmpeg"
        existing.write_text("#!/bin/bash\n# Some other wrapper\necho 'original'")

        config = BrewConfig(wrapper_dir=str(wrapper_dir))

        with patch("gaol.brew.wrapper.get_data_dir", return_value=tmp_path):
            installer = WrapperInstaller(config=config)

            with pytest.raises(WrapperExistsError) as exc_info:
                installer.install("ffmpeg", ["ffmpeg"])

            assert exc_info.value.binary == "ffmpeg"

    def test_install_allows_overwrite_our_wrapper(self, tmp_path: Path) -> None:
        """Test that install overwrites our existing wrapper."""
        wrapper_dir = tmp_path / "bin"
        wrapper_dir.mkdir(parents=True)
        existing = wrapper_dir / "ffmpeg"
        existing.write_text("#!/bin/bash\n# gaol brew run ffmpeg\nold version")

        config = BrewConfig(wrapper_dir=str(wrapper_dir))

        with patch("gaol.brew.wrapper.get_data_dir", return_value=tmp_path):
            installer = WrapperInstaller(config=config)
            installed = installer.install("ffmpeg", ["ffmpeg"])

        assert len(installed) == 1
        # Content should be updated
        content = existing.read_text()
        assert "exec gaol brew run ffmpeg" in content

    def test_install_overwrite_flag(self, tmp_path: Path) -> None:
        """Test that overwrite flag allows replacing any wrapper."""
        wrapper_dir = tmp_path / "bin"
        wrapper_dir.mkdir(parents=True)
        existing = wrapper_dir / "ffmpeg"
        existing.write_text("#!/bin/bash\necho 'not our wrapper'")

        config = BrewConfig(wrapper_dir=str(wrapper_dir))

        with patch("gaol.brew.wrapper.get_data_dir", return_value=tmp_path):
            installer = WrapperInstaller(config=config)
            installed = installer.install("ffmpeg", ["ffmpeg"], overwrite=True)

        assert len(installed) == 1
        content = existing.read_text()
        assert "gaol brew run ffmpeg" in content

    def test_uninstall_removes_wrappers(self, tmp_path: Path) -> None:
        """Test that uninstall removes wrapper scripts."""
        wrapper_dir = tmp_path / "bin"
        config = BrewConfig(wrapper_dir=str(wrapper_dir))

        with patch("gaol.brew.wrapper.get_data_dir", return_value=tmp_path):
            installer = WrapperInstaller(config=config)
            installer.install("ffmpeg", ["ffmpeg", "ffprobe"])

            # Verify they exist
            assert (wrapper_dir / "ffmpeg").exists()
            assert (wrapper_dir / "ffprobe").exists()

            # Uninstall
            removed = installer.uninstall("ffmpeg")

        assert removed == 2
        assert not (wrapper_dir / "ffmpeg").exists()
        assert not (wrapper_dir / "ffprobe").exists()

    def test_uninstall_raises_if_not_found(self, tmp_path: Path) -> None:
        """Test that uninstall raises if package not tracked."""
        config = BrewConfig(wrapper_dir=str(tmp_path / "bin"))

        with patch("gaol.brew.wrapper.get_data_dir", return_value=tmp_path):
            installer = WrapperInstaller(config=config)

            with pytest.raises(WrapperNotFoundError) as exc_info:
                installer.uninstall("nonexistent")

            assert exc_info.value.package == "nonexistent"

    def test_list_installed_empty(self, tmp_path: Path) -> None:
        """Test listing with no installed packages."""
        with patch("gaol.brew.wrapper.get_data_dir", return_value=tmp_path):
            installer = WrapperInstaller()
            entries = installer.list_installed()

        assert entries == []

    def test_list_installed_returns_packages(self, tmp_path: Path) -> None:
        """Test listing installed packages."""
        wrapper_dir = tmp_path / "bin"
        config = BrewConfig(wrapper_dir=str(wrapper_dir))

        with patch("gaol.brew.wrapper.get_data_dir", return_value=tmp_path):
            installer = WrapperInstaller(config=config)
            installer.install("ffmpeg", ["ffmpeg", "ffprobe"])
            installer.install("ripgrep", ["rg"])

            entries = installer.list_installed()

        assert len(entries) == 2
        package_names = [e.package_name for e in entries]
        assert "ffmpeg" in package_names
        assert "ripgrep" in package_names

    def test_list_installed_filter_by_package(self, tmp_path: Path) -> None:
        """Test filtering list by package name."""
        wrapper_dir = tmp_path / "bin"
        config = BrewConfig(wrapper_dir=str(wrapper_dir))

        with patch("gaol.brew.wrapper.get_data_dir", return_value=tmp_path):
            installer = WrapperInstaller(config=config)
            installer.install("ffmpeg", ["ffmpeg"])
            installer.install("ripgrep", ["rg"])

            entries = installer.list_installed(package="ffmpeg")

        assert len(entries) == 1
        assert entries[0].package_name == "ffmpeg"

    def test_get_wrapper_content(self, tmp_path: Path) -> None:
        """Test getting wrapper script content."""
        wrapper_dir = tmp_path / "bin"
        config = BrewConfig(wrapper_dir=str(wrapper_dir))

        with patch("gaol.brew.wrapper.get_data_dir", return_value=tmp_path):
            installer = WrapperInstaller(config=config)
            installer.install("cowsay", ["cowsay"])

            content = installer.get_wrapper_content("cowsay")

        assert content is not None
        assert "gaol brew run cowsay" in content

    def test_get_wrapper_content_not_found(self, tmp_path: Path) -> None:
        """Test getting content for nonexistent wrapper."""
        config = BrewConfig(wrapper_dir=str(tmp_path / "bin"))

        with patch("gaol.brew.wrapper.get_data_dir", return_value=tmp_path):
            installer = WrapperInstaller(config=config)
            content = installer.get_wrapper_content("nonexistent")

        assert content is None


class TestBrewContainer:
    """Tests for Homebrew container management."""

    def test_homebrew_prefix_constant(self) -> None:
        """Test HOMEBREW_PREFIX is set correctly."""
        assert BrewContainer.HOMEBREW_PREFIX == "/home/linuxbrew/.linuxbrew"

    def test_ensure_container_creates_new(self) -> None:
        """Test ensure_container creates container if not exists."""
        with (
            patch("gaol.brew.container.get_container_store") as mock_store,
            patch("gaol.brew.container.get_runtime") as mock_get_runtime,
        ):
            mock_store.return_value.get.return_value = None
            mock_runtime = MagicMock()
            mock_runtime.create.return_value = "container-123"
            mock_runtime.exec.return_value = (0, "", "")
            mock_get_runtime.return_value = mock_runtime

            container = BrewContainer()
            container_id = container.ensure_container()

            assert container_id == "container-123"
            mock_runtime.create.assert_called_once()
            mock_runtime.start.assert_called()

    def test_ensure_container_starts_stopped(self) -> None:
        """Test ensure_container starts a stopped container."""
        from gaol.models.container import ContainerState, ContainerStatus

        with (
            patch("gaol.brew.container.get_container_store") as mock_store,
            patch("gaol.brew.container.get_runtime") as mock_get_runtime,
        ):
            mock_stored = MagicMock()
            mock_stored.container_id = "container-456"
            mock_stored.runtime = "docker"
            mock_store.return_value.get.return_value = mock_stored

            mock_runtime = MagicMock()
            mock_runtime.get_state.return_value = ContainerState(
                id="container-456",
                name="homebrew",
                runtime="docker",
                status=ContainerStatus.STOPPED,
                image="debian:bookworm",
            )
            mock_get_runtime.return_value = mock_runtime

            container = BrewContainer()
            container_id = container.ensure_container()

            assert container_id == "container-456"
            mock_runtime.start.assert_called_once()

    def test_ensure_container_already_running(self) -> None:
        """Test ensure_container returns ID for running container."""
        from gaol.models.container import ContainerState, ContainerStatus

        with (
            patch("gaol.brew.container.get_container_store") as mock_store,
            patch("gaol.brew.container.get_runtime") as mock_get_runtime,
        ):
            mock_stored = MagicMock()
            mock_stored.container_id = "container-789"
            mock_stored.runtime = "docker"
            mock_store.return_value.get.return_value = mock_stored

            mock_runtime = MagicMock()
            mock_runtime.get_state.return_value = ContainerState(
                id="container-789",
                name="homebrew",
                runtime="docker",
                status=ContainerStatus.RUNNING,
                image="debian:bookworm",
            )
            mock_get_runtime.return_value = mock_runtime

            container = BrewContainer()
            container_id = container.ensure_container()

            assert container_id == "container-789"
            mock_runtime.start.assert_not_called()

    def test_install_package(self) -> None:
        """Test installing a Homebrew package."""
        with (
            patch("gaol.brew.container.get_container_store") as mock_store,
            patch("gaol.brew.container.get_runtime") as mock_get_runtime,
        ):
            mock_stored = MagicMock()
            mock_stored.container_id = "container-abc"
            mock_stored.runtime = "docker"
            mock_store.return_value.get.return_value = mock_stored

            mock_runtime = MagicMock()
            from gaol.models.container import ContainerState, ContainerStatus

            mock_runtime.get_state.return_value = ContainerState(
                id="container-abc",
                name="homebrew",
                runtime="docker",
                status=ContainerStatus.RUNNING,
                image="debian:bookworm",
            )
            mock_runtime.exec.return_value = (0, "==> Installing ffmpeg", "")
            mock_get_runtime.return_value = mock_runtime

            container = BrewContainer()
            exit_code, stdout, stderr = container.install_package("ffmpeg")

            assert exit_code == 0
            assert "Installing ffmpeg" in stdout
            mock_runtime.exec.assert_called()
            # Verify brew install command was called
            call_args = mock_runtime.exec.call_args
            assert "brew" in call_args[0][1][0]
            assert "install" in call_args[0][1]
            assert "ffmpeg" in call_args[0][1]

    def test_run_command(self) -> None:
        """Test running a command in the container."""
        with (
            patch("gaol.brew.container.get_container_store") as mock_store,
            patch("gaol.brew.container.get_runtime") as mock_get_runtime,
        ):
            mock_stored = MagicMock()
            mock_stored.container_id = "container-def"
            mock_stored.runtime = "docker"
            mock_store.return_value.get.return_value = mock_stored

            mock_runtime = MagicMock()
            from gaol.models.container import ContainerState, ContainerStatus

            mock_runtime.get_state.return_value = ContainerState(
                id="container-def",
                name="homebrew",
                runtime="docker",
                status=ContainerStatus.RUNNING,
                image="debian:bookworm",
            )
            mock_runtime.exec.return_value = (0, "ffmpeg version 6.1", "")
            mock_get_runtime.return_value = mock_runtime

            container = BrewContainer()
            exit_code, stdout, stderr = container.run_command(
                ["ffmpeg", "-version"], workdir="/home/user"
            )

            assert exit_code == 0
            assert "ffmpeg version" in stdout
            # Verify PATH was set
            call_kwargs = mock_runtime.exec.call_args[1]
            assert "PATH" in call_kwargs.get("environment", {})

    def test_list_installed(self) -> None:
        """Test listing installed Homebrew packages."""
        with (
            patch("gaol.brew.container.get_container_store") as mock_store,
            patch("gaol.brew.container.get_runtime") as mock_get_runtime,
        ):
            mock_stored = MagicMock()
            mock_stored.container_id = "container-ghi"
            mock_stored.runtime = "docker"
            mock_store.return_value.get.return_value = mock_stored

            mock_runtime = MagicMock()
            from gaol.models.container import ContainerState, ContainerStatus

            mock_runtime.get_state.return_value = ContainerState(
                id="container-ghi",
                name="homebrew",
                runtime="docker",
                status=ContainerStatus.RUNNING,
                image="debian:bookworm",
            )
            mock_runtime.exec.return_value = (0, "ffmpeg\nripgrep\ncowsay\n", "")
            mock_get_runtime.return_value = mock_runtime

            container = BrewContainer()
            packages = container.list_installed()

            assert len(packages) == 3
            assert "ffmpeg" in packages
            assert "ripgrep" in packages
            assert "cowsay" in packages

    def test_list_installed_empty(self) -> None:
        """Test listing when no packages installed."""
        with (
            patch("gaol.brew.container.get_container_store") as mock_store,
            patch("gaol.brew.container.get_runtime") as mock_get_runtime,
        ):
            mock_stored = MagicMock()
            mock_stored.container_id = "container-jkl"
            mock_stored.runtime = "docker"
            mock_store.return_value.get.return_value = mock_stored

            mock_runtime = MagicMock()
            from gaol.models.container import ContainerState, ContainerStatus

            mock_runtime.get_state.return_value = ContainerState(
                id="container-jkl",
                name="homebrew",
                runtime="docker",
                status=ContainerStatus.RUNNING,
                image="debian:bookworm",
            )
            mock_runtime.exec.return_value = (0, "", "")
            mock_get_runtime.return_value = mock_runtime

            container = BrewContainer()
            packages = container.list_installed()

            assert packages == []

    def test_list_installed_no_container(self) -> None:
        """Test listing when container doesn't exist."""
        with patch("gaol.brew.container.get_container_store") as mock_store:
            mock_store.return_value.get.return_value = None

            container = BrewContainer()
            packages = container.list_installed()

            assert packages == []

    def test_get_package_binaries(self) -> None:
        """Test discovering binaries for a package."""
        with (
            patch("gaol.brew.container.get_container_store") as mock_store,
            patch("gaol.brew.container.get_runtime") as mock_get_runtime,
        ):
            mock_stored = MagicMock()
            mock_stored.container_id = "container-mno"
            mock_stored.runtime = "docker"
            mock_store.return_value.get.return_value = mock_stored

            mock_runtime = MagicMock()
            from gaol.models.container import ContainerState, ContainerStatus

            mock_runtime.get_state.return_value = ContainerState(
                id="container-mno",
                name="homebrew",
                runtime="docker",
                status=ContainerStatus.RUNNING,
                image="debian:bookworm",
            )
            # First call: brew --prefix ffmpeg
            # Second call: ls -1 bin_dir
            mock_runtime.exec.side_effect = [
                (0, "/home/linuxbrew/.linuxbrew/Cellar/ffmpeg/6.1", ""),
                (0, "ffmpeg\nffprobe\nffplay\n", ""),
            ]
            mock_get_runtime.return_value = mock_runtime

            container = BrewContainer()
            binaries = container.get_package_binaries("ffmpeg")

            assert len(binaries) == 3
            assert "ffmpeg" in binaries
            assert "ffprobe" in binaries
            assert "ffplay" in binaries

    def test_get_package_binaries_fallback(self) -> None:
        """Test fallback to package name if bin discovery fails."""
        with (
            patch("gaol.brew.container.get_container_store") as mock_store,
            patch("gaol.brew.container.get_runtime") as mock_get_runtime,
        ):
            mock_stored = MagicMock()
            mock_stored.container_id = "container-pqr"
            mock_stored.runtime = "docker"
            mock_store.return_value.get.return_value = mock_stored

            mock_runtime = MagicMock()
            from gaol.models.container import ContainerState, ContainerStatus

            mock_runtime.get_state.return_value = ContainerState(
                id="container-pqr",
                name="homebrew",
                runtime="docker",
                status=ContainerStatus.RUNNING,
                image="debian:bookworm",
            )
            # Prefix lookup fails
            mock_runtime.exec.return_value = (1, "", "not found")
            mock_get_runtime.return_value = mock_runtime

            container = BrewContainer()
            binaries = container.get_package_binaries("somepackage")

            # Should fall back to package name
            assert binaries == ["somepackage"]

    def test_search(self) -> None:
        """Test searching for packages."""
        with (
            patch("gaol.brew.container.get_container_store") as mock_store,
            patch("gaol.brew.container.get_runtime") as mock_get_runtime,
        ):
            mock_stored = MagicMock()
            mock_stored.container_id = "container-stu"
            mock_stored.runtime = "docker"
            mock_store.return_value.get.return_value = mock_stored

            mock_runtime = MagicMock()
            from gaol.models.container import ContainerState, ContainerStatus

            mock_runtime.get_state.return_value = ContainerState(
                id="container-stu",
                name="homebrew",
                runtime="docker",
                status=ContainerStatus.RUNNING,
                image="debian:bookworm",
            )
            mock_runtime.exec.return_value = (0, "ffmpeg\nffmpeg2theora\n", "")
            mock_get_runtime.return_value = mock_runtime

            container = BrewContainer()
            exit_code, stdout, stderr = container.search("ffmpeg")

            assert exit_code == 0
            assert "ffmpeg" in stdout

    def test_info(self) -> None:
        """Test getting package info."""
        with (
            patch("gaol.brew.container.get_container_store") as mock_store,
            patch("gaol.brew.container.get_runtime") as mock_get_runtime,
        ):
            mock_stored = MagicMock()
            mock_stored.container_id = "container-vwx"
            mock_stored.runtime = "docker"
            mock_store.return_value.get.return_value = mock_stored

            mock_runtime = MagicMock()
            from gaol.models.container import ContainerState, ContainerStatus

            mock_runtime.get_state.return_value = ContainerState(
                id="container-vwx",
                name="homebrew",
                runtime="docker",
                status=ContainerStatus.RUNNING,
                image="debian:bookworm",
            )
            mock_runtime.exec.return_value = (
                0,
                "==> ffmpeg: stable 6.1 (bottled)\n",
                "",
            )
            mock_get_runtime.return_value = mock_runtime

            container = BrewContainer()
            exit_code, stdout, stderr = container.info("ffmpeg")

            assert exit_code == 0
            assert "ffmpeg" in stdout
            assert "6.1" in stdout

    def test_is_container_ready(self) -> None:
        """Test checking if container is ready."""
        with patch("gaol.brew.container.get_container_store") as mock_store:
            # Container exists
            mock_store.return_value.get.return_value = MagicMock()
            container = BrewContainer()
            assert container.is_container_ready() is True

            # Container doesn't exist
            mock_store.return_value.get.return_value = None
            assert container.is_container_ready() is False

    def test_ensure_container_raises_on_failure(self) -> None:
        """Test ensure_container raises on creation failure."""
        with (
            patch("gaol.brew.container.get_container_store") as mock_store,
            patch("gaol.brew.container.get_runtime") as mock_get_runtime,
        ):
            mock_store.return_value.get.return_value = None
            mock_runtime = MagicMock()
            mock_runtime.create.side_effect = Exception("Docker daemon not running")
            mock_get_runtime.return_value = mock_runtime

            container = BrewContainer()

            with pytest.raises(BrewContainerError) as exc_info:
                container.ensure_container()

            assert "Failed to create container" in str(exc_info.value)


class TestBrewCLI:
    """Tests for brew CLI commands."""

    def test_brew_help(self) -> None:
        """Test brew subcommand help."""
        from gaol.cli import app

        runner = CliRunner()
        result = runner.invoke(app, ["brew", "--help"])
        assert result.exit_code == 0
        assert "Homebrew" in result.output

    def test_brew_install_help(self) -> None:
        """Test brew install help."""
        from gaol.cli import app

        runner = CliRunner()
        result = runner.invoke(app, ["brew", "install", "--help"])
        assert result.exit_code == 0
        assert "Install" in result.output

    def test_brew_run_help(self) -> None:
        """Test brew run help."""
        from gaol.cli import app

        runner = CliRunner()
        result = runner.invoke(app, ["brew", "run", "--help"])
        assert result.exit_code == 0
        assert "Run" in result.output or "binary" in result.output.lower()

    def test_brew_list_help(self) -> None:
        """Test brew list help."""
        from gaol.cli import app

        runner = CliRunner()
        result = runner.invoke(app, ["brew", "list", "--help"])
        assert result.exit_code == 0
        assert "List" in result.output or "installed" in result.output.lower()

    def test_brew_uninstall_help(self) -> None:
        """Test brew uninstall help."""
        from gaol.cli import app

        runner = CliRunner()
        result = runner.invoke(app, ["brew", "uninstall", "--help"])
        assert result.exit_code == 0
        assert "Uninstall" in result.output or "uninstall" in result.output.lower()

    def test_brew_search_help(self) -> None:
        """Test brew search help."""
        from gaol.cli import app

        runner = CliRunner()
        result = runner.invoke(app, ["brew", "search", "--help"])
        assert result.exit_code == 0
        assert "Search" in result.output or "search" in result.output.lower()

    def test_brew_info_help(self) -> None:
        """Test brew info help."""
        from gaol.cli import app

        runner = CliRunner()
        result = runner.invoke(app, ["brew", "info", "--help"])
        assert result.exit_code == 0
        assert "info" in result.output.lower() or "package" in result.output.lower()

    def test_brew_list_empty(self, tmp_path: Path) -> None:
        """Test listing with no wrappers."""
        from gaol.cli import app

        runner = CliRunner()

        with patch("gaol.brew.wrapper.get_data_dir", return_value=tmp_path):
            result = runner.invoke(app, ["brew", "list"])

        assert result.exit_code == 0
        assert "No wrapper" in result.output or "No packages" in result.output.lower()

    def test_brew_list_all_no_container(self) -> None:
        """Test listing all with no container."""
        from gaol.cli import app

        runner = CliRunner()

        with patch("gaol.brew.container.get_container_store") as mock_store:
            mock_store.return_value.get.return_value = None
            result = runner.invoke(app, ["brew", "list", "--all"])

        assert result.exit_code == 0
        assert "No Homebrew" in result.output or "No packages" in result.output.lower()


class TestWrapperScriptGeneration:
    """Tests for wrapper script content generation."""

    def test_wrapper_script_format(self, tmp_path: Path) -> None:
        """Test wrapper script has correct format."""
        wrapper_dir = tmp_path / "bin"
        config = BrewConfig(wrapper_dir=str(wrapper_dir))

        with patch("gaol.brew.wrapper.get_data_dir", return_value=tmp_path):
            installer = WrapperInstaller(config=config)
            installer.install("test-pkg", ["testcmd"])

        content = (wrapper_dir / "testcmd").read_text()
        lines = content.strip().split("\n")

        # First line should be shebang
        assert lines[0] == "#!/bin/bash"
        # Should have comment indicating it's auto-generated
        assert any("auto-generated" in line.lower() for line in lines)
        # Should exec gaol brew run
        assert any("exec gaol brew run testcmd" in line for line in lines)
        # Should pass arguments
        assert any('"$@"' in line for line in lines)

    def test_wrapper_includes_binary_name_in_comment(self, tmp_path: Path) -> None:
        """Test wrapper has binary name in comment."""
        wrapper_dir = tmp_path / "bin"
        config = BrewConfig(wrapper_dir=str(wrapper_dir))

        with patch("gaol.brew.wrapper.get_data_dir", return_value=tmp_path):
            installer = WrapperInstaller(config=config)
            installer.install("ffmpeg", ["ffmpeg"])

        content = (wrapper_dir / "ffmpeg").read_text()
        assert "ffmpeg" in content


class TestBrewContainerConfig:
    """Tests for container configuration."""

    def test_container_mounts_home_by_default(self) -> None:
        """Test container mounts home directory by default."""
        config = BrewConfig()
        assert config.mount_home is True

    def test_container_uses_bookworm_by_default(self) -> None:
        """Test container uses Debian Bookworm by default."""
        config = BrewConfig()
        assert config.distro == "bookworm"

    def test_container_disables_analytics(self) -> None:
        """Test container sets Homebrew analytics off."""
        # This is tested by checking the container creation
        # The environment should include HOMEBREW_NO_ANALYTICS=1
        with (
            patch("gaol.brew.container.get_container_store") as mock_store,
            patch("gaol.brew.container.get_runtime") as mock_get_runtime,
        ):
            mock_store.return_value.get.return_value = None
            mock_runtime = MagicMock()
            mock_runtime.create.return_value = "container-test"
            mock_runtime.exec.return_value = (0, "", "")
            mock_get_runtime.return_value = mock_runtime

            container = BrewContainer()
            container.ensure_container()

            # Check the config passed to create
            call_args = mock_runtime.create.call_args
            config = call_args[0][0]
            assert config.environment.get("HOMEBREW_NO_ANALYTICS") == "1"
            assert config.environment.get("HOMEBREW_NO_AUTO_UPDATE") == "1"
