"""
Host and software checking utilities
"""

import subprocess
import os
from typing import Dict, List


class HostManager:
    """Manages host system checks and software detection"""

    @staticmethod
    def run_command(cmd: str) -> str:
        """Run shell command and return output"""
        try:
            result = subprocess.run(
                cmd, shell=True, capture_output=True, text=True, check=True
            )
            return result.stdout.strip()
        except subprocess.CalledProcessError:
            return ""

    @staticmethod
    def check_command(cmd: str) -> bool:
        """Check if a command is available"""
        return HostManager.run_command(f"which {cmd} > /dev/null 2>&1 && echo yes") == "yes"

    @staticmethod
    def get_package_version(package: str) -> str:
        """Get version of an installed package"""
        try:
            if package == "docker":
                output = HostManager.run_command("docker --version")
                return output
            elif package == "git":
                output = HostManager.run_command("git --version")
                return output
            elif package == "gh":
                output = HostManager.run_command("gh --version")
                return output
            elif package == "ubuntu-desktop":
                # Check if ubuntu-desktop is installed
                output = HostManager.run_command("dpkg -l | grep ubuntu-desktop")
                return "Installed" if output else "Not installed"
            elif package == "docker-compose":
                output = HostManager.run_command("docker-compose --version 2>/dev/null || docker compose version")
                return output if output else "Not installed"
            return "Unknown"
        except:
            return "Not installed"

    @staticmethod
    def get_system_info() -> Dict[str, str]:
        """Get system information"""
        info = {}

        # OS info
        info["os"] = HostManager.run_command("lsb_release -ds 2>/dev/null || cat /etc/os-release | grep PRETTY_NAME | cut -d= -f2").strip('"')
        info["kernel"] = HostManager.run_command("uname -r")
        info["hostname"] = HostManager.run_command("hostname")
        info["arch"] = HostManager.run_command("uname -m")

        # User info
        info["user"] = os.environ.get("USER", os.environ.get("USERNAME", "unknown"))
        info["home"] = os.path.expanduser("~")

        # Uptime
        uptime_raw = HostManager.run_command("uptime -p 2>/dev/null || uptime").replace("up ", "")
        info["uptime"] = uptime_raw

        # CPU info
        info["cpu"] = HostManager.run_command("lscpu | grep 'Model name:' | cut -d: -f2 | xargs || echo 'Unknown'")

        # Memory info
        mem_raw = HostManager.run_command("free -h | grep Mem:")
        if mem_raw:
            parts = mem_raw.split()
            info["memory"] = f"{parts[1]} total, {parts[2]} used, {parts[3]} available"
        else:
            info["memory"] = "Unknown"

        # Disk info
        disk_raw = HostManager.run_command("df -h / | tail -1")
        if disk_raw:
            parts = disk_raw.split()
            info["disk"] = f"{parts[1]} total, {parts[2]} used, {parts[3]} available ({parts[4]})"
        else:
            info["disk"] = "Unknown"

        # Load average
        load_raw = HostManager.run_command("cat /proc/loadavg")
        if load_raw:
            load_parts = load_raw.split()[:3]
            info["load"] = ", ".join(load_parts)
        else:
            info["load"] = "Unknown"

        return info

    @staticmethod
    def get_docker_info() -> Dict[str, str]:
        """Get Docker information"""
        info = {}

        if not HostManager.check_command("docker"):
            return {"status": "Not installed"}

        try:
            # Docker version
            info["version"] = HostManager.run_command("docker --version")

            # Docker info
            docker_info = HostManager.run_command("docker info")
            if docker_info:
                info["status"] = "Running"

                # Parse some useful info
                for line in docker_info.split("\n"):
                    if "Server Version:" in line:
                        info["server_version"] = line.split(":", 1)[1].strip()
                    elif "Storage Driver:" in line:
                        info["storage_driver"] = line.split(":", 1)[1].strip()
                    elif "containers:" in line.lower():
                        info["containers"] = line.split(":", 1)[1].strip()
        except:
            info["status"] = "Error"

        return info

    @staticmethod
    def check_required_software() -> List[Dict[str, str]]:
        """Check status of required software with install/uninstall commands"""
        required = [
            {
                "name": "Docker",
                "key": "docker",
                "check": "docker",
                "install_cmd": "curl -fsSL https://get.docker.com | sudo sh && sudo usermod -aG docker $USER",
                "uninstall_cmd": "sudo apt-get remove -y docker-ce docker-ce-cli containerd.io"
            },
            {
                "name": "Docker Compose",
                "key": "docker-compose",
                "check": "docker-compose",
                "install_cmd": "sudo apt-get update && sudo apt-get install -y docker-compose-plugin",
                "uninstall_cmd": "sudo apt-get remove -y docker-compose-plugin"
            },
            {
                "name": "Git",
                "key": "git",
                "check": "git",
                "install_cmd": "sudo apt-get update && sudo apt-get install -y git",
                "uninstall_cmd": "sudo apt-get remove -y git"
            },
            {
                "name": "GitHub CLI",
                "key": "gh",
                "check": "gh",
                # GitHub CLI: Official installation via apt (not snap)
                # 1. Create keyrings directory
                # 2. Download GPG key to /etc/apt/keyrings/
                # 3. Add apt source
                # 4. Install via apt
                "install_cmd": "sudo mkdir -p -m 755 /etc/apt/keyrings && wget -qO- https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo tee /etc/apt/keyrings/githubcli-archive-keyring.gpg > /dev/null && sudo chmod go+r /etc/apt/keyrings/githubcli-archive-keyring.gpg && echo 'deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main' | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null && sudo apt update && sudo apt install -y gh",
                "uninstall_cmd": "sudo apt remove -y gh && sudo rm -f /etc/apt/sources.list.d/github-cli.list /etc/apt/keyrings/githubcli-archive-keyring.gpg"
            },
            {
                "name": "Python 3",
                "key": "python3",
                "check": "python3",
                "install_cmd": "sudo apt-get update && sudo apt-get install -y python3 python3-pip python3-venv",
                "uninstall_cmd": None  # Don't allow uninstalling Python
            },
            {
                "name": "Ubuntu Desktop",
                "key": "ubuntu-desktop",
                "check": "ubuntu-desktop",
                "install_cmd": "sudo apt-get update && sudo apt-get install -y ubuntu-desktop",
                "uninstall_cmd": "sudo apt-get remove -y ubuntu-desktop"
            },
            {
                "name": "N|Solid",
                "key": "nsolid",
                "check": "nsolid",
                # N|Solid: NodeSource's enterprise Node.js runtime with monitoring
                # 1. Downloads setup script from NodeSource
                # 2. Adds NodeSource apt repository to system
                # 3. Installs nsolid package (replaces/aliases 'node' command)
                "install_cmd": "curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash - && sudo apt-get install -y nsolid",
                "uninstall_cmd": "sudo apt-get purge -y nsolid && sudo rm -f /etc/apt/sources.list.d/nodesource.list"
            },
            {
                "name": "pnpm",
                "key": "pnpm",
                "check": "pnpm",
                # pnpm: Fast, disk-efficient package manager (user install)
                # 1. Downloads install script from pnpm.io
                # 2. Installs to ~/.local/share/pnpm
                # 3. Adds pnpm to shell PATH automatically
                "install_cmd": "curl -fsSL https://get.pnpm.io/install.sh | sh -",
                "uninstall_cmd": "rm -rf ~/.local/share/pnpm ~/.pnpm-store"
            },
            {
                "name": "Claude Code",
                "key": "claude",
                "check": "claude",
                # Claude Code: Anthropic's CLI tool (user install via npm)
                # 1. Creates ~/.npm-global for user-level global packages
                # 2. Configures npm to use this prefix
                # 3. Installs claude-code globally for current user
                # 4. Adds ~/.npm-global/bin to PATH in .bashrc (if not already present)
                "install_cmd": "mkdir -p ~/.npm-global && npm config set prefix '~/.npm-global' && npm install -g @anthropic-ai/claude-code && python3 -c \"\nimport os\npath_line = 'export PATH=\\\"\\$HOME/.npm-global/bin:\\$PATH\\\"'\nbashrc = os.path.expanduser('~/.bashrc')\nif os.path.exists(bashrc):\n    with open(bashrc) as f:\n        content = f.read()\n    if '.npm-global/bin' not in content:\n        with open(bashrc, 'a') as f:\n            f.write('\\\\n# Added by infra-cli for npm global packages\\\\n')\n            f.write(path_line + '\\\\n')\n        print('Added ~/.npm-global/bin to PATH in ~/.bashrc')\n    else:\n        print('PATH already configured in ~/.bashrc')\n\"",
                "uninstall_cmd": "npm uninstall -g @anthropic-ai/claude-code"
            },
            {
                "name": "ttyd",
                "key": "ttyd",
                "check": "ttyd",
                # ttyd: Share terminal over web with basic auth support
                # Used by infra-tui to provide web-based access
                "install_cmd": "sudo apt-get update && sudo apt-get install -y ttyd",
                "uninstall_cmd": "sudo apt-get remove -y ttyd"
            },
        ]

        results = []
        for item in required:
            key = item["key"]

            # Special checks for non-command items
            if key == "ubuntu-desktop":
                # Check if package is installed via dpkg
                installed = HostManager.run_command("dpkg -l ubuntu-desktop 2>/dev/null | grep -q '^ii' && echo yes") == "yes"
            elif key == "docker-compose":
                # Docker Compose v2 is a plugin, check with 'docker compose version'
                installed = HostManager.run_command("docker compose version >/dev/null 2>&1 && echo yes") == "yes"
            else:
                check_cmd = item.get("check", key)
                installed = HostManager.check_command(check_cmd)

            version = HostManager._get_software_version(key) if installed else "Not installed"

            results.append({
                "name": item["name"],
                "key": key,
                "installed": installed,
                "version": version,
                "install_cmd": item.get("install_cmd"),
                "uninstall_cmd": item.get("uninstall_cmd")
            })

        return results

    @staticmethod
    def _get_software_version(key: str) -> str:
        """Get version of installed software"""
        version_cmds = {
            "docker": "docker --version 2>/dev/null | head -1",
            "docker-compose": "docker compose version 2>/dev/null | head -1",
            "git": "git --version 2>/dev/null",
            "gh": "gh --version 2>/dev/null | head -1",
            "python3": "python3 --version 2>/dev/null",
            "ubuntu-desktop": "dpkg -l ubuntu-desktop 2>/dev/null | grep '^ii' | awk '{print $3}'",
            "nsolid": "nsolid --version 2>/dev/null",
            "pnpm": "pnpm --version 2>/dev/null",
            "claude": "claude --version 2>/dev/null || echo 'Installed'",
            "ttyd": "ttyd --version 2>/dev/null | awk '{print $NF}'"
        }
        cmd = version_cmds.get(key)
        if cmd:
            return HostManager.run_command(cmd) or "Installed"
        return "Installed"
