"""Homebrew container management.

This module handles the lifecycle of the Homebrew container,
including creation, package installation, and command execution.
"""

from __future__ import annotations

from pathlib import Path

from gaol.brew.exceptions import BrewContainerError, BrewInstallError
from gaol.brew.models import BrewConfig
from gaol.models.container import ContainerConfig, ContainerStatus
from gaol.runtimes import get_runtime
from gaol.store import get_container_store


class BrewContainer:
    """Manage the Homebrew container.

    Handles container creation, Homebrew installation, package management,
    and command execution within the container.

    Example:
        >>> container = BrewContainer()
        >>> container.install_package("ffmpeg")
        >>> exit_code, stdout, stderr = container.run_command(["ffmpeg", "-version"])
    """

    HOMEBREW_PREFIX = "/home/linuxbrew/.linuxbrew"

    def __init__(self, config: BrewConfig | None = None) -> None:
        """Initialize the Homebrew container manager.

        Args:
            config: Optional configuration for the container.
        """
        self.config = config or BrewConfig()
        self.store = get_container_store()

    def ensure_container(self) -> str:
        """Ensure Homebrew container exists and is running.

        Creates the container if it doesn't exist, starts it if stopped.

        Returns:
            Container ID.

        Raises:
            BrewContainerError: If container cannot be created or started.
        """
        stored = self.store.get(self.config.container_name)

        if not stored:
            return self._create_container()

        runtime = get_runtime(stored.runtime)

        try:
            state = runtime.get_state(self.config.container_name)
        except Exception as e:
            raise BrewContainerError(f"Failed to get container state: {e}") from e

        if state.status != ContainerStatus.RUNNING:
            try:
                runtime.start(self.config.container_name)
                self.store.update_started(self.config.container_name)
            except Exception as e:
                raise BrewContainerError(f"Failed to start container: {e}") from e

        return stored.container_id

    def _create_container(self) -> str:
        """Create the Homebrew container with proper mounts.

        Returns:
            Container ID.

        Raises:
            BrewContainerError: If container creation fails.
        """
        home = str(Path.home())

        config = ContainerConfig(
            name=self.config.container_name,
            runtime=self.config.runtime,
            distro=self.config.distro,
            profiles=["base"],
            volumes={home: home} if self.config.mount_home else {},
            environment={
                "HOMEBREW_NO_ANALYTICS": "1",
                "HOMEBREW_NO_AUTO_UPDATE": "1",
            },
        )

        runtime = get_runtime(self.config.runtime)

        try:
            container_id = runtime.create(config)
            self.store.save(config, container_id, self.config.runtime)

            # Start the container
            runtime.start(container_id)
            self.store.update_started(self.config.container_name)

            # Install Homebrew
            self._install_homebrew(container_id, runtime)

            return container_id
        except Exception as e:
            raise BrewContainerError(f"Failed to create container: {e}") from e

    def _install_homebrew(self, container_id: str, runtime) -> None:
        """Install Homebrew in the container.

        Args:
            container_id: Container to install Homebrew in.
            runtime: Runtime instance.

        Raises:
            BrewContainerError: If Homebrew installation fails.
        """
        # Install dependencies
        exit_code, _, stderr = runtime.exec(
            container_id,
            ["apt-get", "update"],
        )
        if exit_code != 0:
            raise BrewContainerError(f"Failed to update apt: {stderr}")

        exit_code, _, stderr = runtime.exec(
            container_id,
            [
                "apt-get",
                "install",
                "-y",
                "build-essential",
                "procps",
                "curl",
                "file",
                "git",
            ],
        )
        if exit_code != 0:
            raise BrewContainerError(f"Failed to install dependencies: {stderr}")

        # Install Homebrew (non-interactive)
        exit_code, _, stderr = runtime.exec(
            container_id,
            [
                "/bin/bash",
                "-c",
                'NONINTERACTIVE=1 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"',
            ],
        )
        if exit_code != 0:
            raise BrewContainerError(f"Failed to install Homebrew: {stderr}")

    def install_package(self, package: str) -> tuple[int, str, str]:
        """Install a Homebrew package.

        Args:
            package: Homebrew formula name to install.

        Returns:
            Tuple of (exit_code, stdout, stderr).

        Raises:
            BrewInstallError: If package installation fails.
        """
        container_id = self.ensure_container()
        runtime = get_runtime(self.config.runtime)

        return runtime.exec(
            container_id,
            [f"{self.HOMEBREW_PREFIX}/bin/brew", "install", package],
        )

    def uninstall_package(self, package: str) -> tuple[int, str, str]:
        """Uninstall a Homebrew package.

        Args:
            package: Homebrew formula name to uninstall.

        Returns:
            Tuple of (exit_code, stdout, stderr).
        """
        container_id = self.ensure_container()
        runtime = get_runtime(self.config.runtime)

        return runtime.exec(
            container_id,
            [f"{self.HOMEBREW_PREFIX}/bin/brew", "uninstall", package],
        )

    def run_command(
        self,
        command: list[str],
        workdir: str | None = None,
    ) -> tuple[int, str, str]:
        """Run a command in the Homebrew container.

        Args:
            command: Command and arguments to run.
            workdir: Working directory inside container.

        Returns:
            Tuple of (exit_code, stdout, stderr).
        """
        container_id = self.ensure_container()
        runtime = get_runtime(self.config.runtime)

        # Prepend Homebrew bin to PATH
        env = {
            "PATH": f"{self.HOMEBREW_PREFIX}/bin:{self.HOMEBREW_PREFIX}/sbin:/usr/local/bin:/usr/bin:/bin",
        }

        return runtime.exec(
            container_id,
            command,
            workdir=workdir,
            environment=env,
        )

    def list_installed(self) -> list[str]:
        """List installed Homebrew packages.

        Returns:
            List of installed package names.
        """
        stored = self.store.get(self.config.container_name)
        if not stored:
            return []

        container_id = self.ensure_container()
        runtime = get_runtime(self.config.runtime)

        exit_code, stdout, stderr = runtime.exec(
            container_id,
            [f"{self.HOMEBREW_PREFIX}/bin/brew", "list", "--formula", "-1"],
        )

        if exit_code != 0:
            return []

        return [p.strip() for p in stdout.strip().split("\n") if p.strip()]

    def get_package_binaries(self, package: str) -> list[str]:
        """Get list of binaries provided by a package.

        Args:
            package: Package name.

        Returns:
            List of binary names provided by the package.
        """
        container_id = self.ensure_container()
        runtime = get_runtime(self.config.runtime)

        # Get package prefix
        exit_code, stdout, stderr = runtime.exec(
            container_id,
            [f"{self.HOMEBREW_PREFIX}/bin/brew", "--prefix", package],
        )

        if exit_code != 0:
            return [package]  # Fallback to package name

        prefix = stdout.strip()
        bin_dir = f"{prefix}/bin"

        # List binaries in the package's bin directory
        exit_code, stdout, stderr = runtime.exec(
            container_id,
            ["ls", "-1", bin_dir],
        )

        if exit_code != 0:
            return [package]  # Fallback to package name

        binaries = [b.strip() for b in stdout.strip().split("\n") if b.strip()]
        return binaries if binaries else [package]

    def search(self, query: str) -> tuple[int, str, str]:
        """Search for Homebrew packages.

        Args:
            query: Search query.

        Returns:
            Tuple of (exit_code, stdout, stderr).
        """
        container_id = self.ensure_container()
        runtime = get_runtime(self.config.runtime)

        return runtime.exec(
            container_id,
            [f"{self.HOMEBREW_PREFIX}/bin/brew", "search", query],
        )

    def info(self, package: str) -> tuple[int, str, str]:
        """Get information about a package.

        Args:
            package: Package name.

        Returns:
            Tuple of (exit_code, stdout, stderr).
        """
        container_id = self.ensure_container()
        runtime = get_runtime(self.config.runtime)

        return runtime.exec(
            container_id,
            [f"{self.HOMEBREW_PREFIX}/bin/brew", "info", package],
        )

    def is_container_ready(self) -> bool:
        """Check if the Homebrew container exists and is ready.

        Returns:
            True if container exists and has Homebrew installed.
        """
        stored = self.store.get(self.config.container_name)
        return stored is not None
