"""Utility functions for electron-angle-patcher."""

from __future__ import annotations

import logging
import os
import subprocess
from pathlib import Path

from electron_angle_patcher.config import Config

logger = logging.getLogger(__name__)


def setup_logging(verbose: bool = False) -> None:
    """Configure logging for the application.

    Args:
        verbose: Enable DEBUG level logging if True, otherwise INFO.
    """
    level = logging.DEBUG if verbose else logging.INFO
    logging.basicConfig(
        level=level,
        format="%(message)s",
        handlers=[logging.StreamHandler()],
    )


def is_running_as_root() -> bool:
    """Check if the script is running with root privileges.

    Returns:
        True if running as root, False otherwise.
    """
    return os.geteuid() == 0


def can_write_to_path(path: Path) -> bool:
    """Check if we have write permissions to the parent directory.

    Args:
        path: The path to check write permissions for.

    Returns:
        True if writable, False otherwise.
    """
    return os.access(path.parent, os.W_OK)


def get_network_mounts() -> set[Path]:
    """Get a set of network mounted volumes on macOS.

    Returns:
        Set of mount points that are network-mounted.
    """
    try:
        result = subprocess.run(
            ["mount"],
            capture_output=True,
            text=True,
            check=False,
        )
    except (subprocess.SubprocessError, FileNotFoundError) as e:
        logger.debug("Failed to detect network mounts: %s", e)
        return set()

    network_mounts = set()
    for line in result.stdout.splitlines():
        if any(fs in line for fs in Config.NETWORK_FS_TYPES):
            try:
                parts = line.split(" on ")
                if len(parts) > 1:
                    mount_point = parts[1].split()[0]
                    network_mounts.add(Path(mount_point))
            except (IndexError, OSError):
                continue

    return network_mounts


def strip_extended_attributes(app_path: Path) -> bool:
    """Strip extended attributes from an application bundle.

    Args:
        app_path: Path to the application bundle.

    Returns:
        True if successful, False otherwise.
    """
    try:
        subprocess.run(
            ["xattr", "-cr", str(app_path)],
            check=False,
            capture_output=True,
        )
        return True
    except (subprocess.SubprocessError, FileNotFoundError) as e:
        logger.debug("Could not strip attributes: %s", e)
        return False


def resign_application(app_path: Path) -> bool:
    """Re-sign an application bundle with ad-hoc signature.

    Args:
        app_path: Path to the application bundle.

    Returns:
        True if successful, False otherwise.
    """
    try:
        result = subprocess.run(
            ["codesign", "--force", "--deep", "--sign", "-", str(app_path)],
            check=False,
            capture_output=True,
            text=True,
        )
        if result.returncode == 0:
            logger.debug("Re-signed application successfully")
            return True
        else:
            logger.debug("codesign returned code %d", result.returncode)
            return False
    except (subprocess.SubprocessError, FileNotFoundError) as e:
        logger.debug("Could not re-sign: %s", e)
        return False


def extract_app_name(file_path: Path, start_dir: Path) -> str:
    """Extract application name from a Local State file path.

    Args:
        file_path: Path to the Local State file.
        start_dir: Root directory for relative path calculation.

    Returns:
        Extracted application name.
    """
    try:
        relative_path = file_path.parent.relative_to(start_dir)
    except ValueError:
        return file_path.parent.name

    parts = list(relative_path.parts)

    # Skip generic folder names when extracting the app name
    for part in reversed(parts):
        if part not in Config.GENERIC_FOLDER_NAMES:
            return part

    return parts[-1] if parts else file_path.parent.name


def kill_app_by_name(app_name: str) -> bool:
    """Kill all running instances of an application by name.

    Args:
        app_name: Name of the application to kill (e.g., "Brave Browser", "Slack").

    Returns:
        True if any processes were killed, False otherwise.
    """
    try:
        # Try pkill first (more reliable for matching by app name)
        result = subprocess.run(
            ["pkill", "-9", app_name],
            capture_output=True,
            text=True,
            check=False,
        )

        # pkill returns 0 if processes were found and killed, 1 if none found
        if result.returncode == 0:
            logger.info("  Killed running instances of %s", app_name)
            return True
        else:
            logger.debug("  No running instances of %s found", app_name)
            return False

    except (subprocess.SubprocessError, FileNotFoundError) as e:
        logger.debug("  Failed to kill %s: %s", app_name, e)
        return False
