"""
User and group management for infra-services
"""

import subprocess
import os
from typing import List


class UserManager:
    """Manages users and groups for infra-services"""

    GROUP_NAME = "infra-users"
    DOCKER_GROUP = "docker"

    @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 group_exists() -> bool:
        """Check if infra-users group exists"""
        groups = UserManager.run_command("getent group infra-users")
        return bool(groups)

    @staticmethod
    def create_group() -> bool:
        """Create the infra-users group (requires sudo)"""
        if UserManager.group_exists():
            return True

        print(f"Creating '{UserManager.GROUP_NAME}' group (requires sudo)...")
        cmd = f"sudo groupadd {UserManager.GROUP_NAME}"
        result = UserManager.run_command(cmd)
        return result is not None or UserManager.group_exists()

    @staticmethod
    def get_group_members() -> List[str]:
        """Get list of users in the infra-users group"""
        if not UserManager.group_exists():
            return []

        output = UserManager.run_command(f"getent group {UserManager.GROUP_NAME}")
        if not output:
            return []

        # Format: group:x:gid:user1,user2,...
        parts = output.split(":")
        if len(parts) >= 4:
            users_str = parts[3]
            return [u.strip() for u in users_str.split(",") if u.strip()]

        return []

    @staticmethod
    def is_user_in_group(username: str = None, group_name: str = None) -> bool:
        """Check if a user is in a group

        Args:
            username: Username to check (defaults to current user)
            group_name: Group to check (defaults to infra-users)
        """
        if username is None:
            username = os.environ.get("USER", os.environ.get("USERNAME", ""))
        if group_name is None:
            group_name = UserManager.GROUP_NAME

        if not username:
            return False

        # Get user's groups
        groups = UserManager.run_command(f"groups {username} 2>/dev/null")
        if groups:
            group_list = groups.split(":")[1].strip().split() if ":" in groups else groups.split()
            return group_name in group_list
        return False

    @staticmethod
    def is_in_docker_group(username: str = None) -> bool:
        """Check if a user is in the docker group"""
        return UserManager.is_user_in_group(username, UserManager.DOCKER_GROUP)

    @staticmethod
    def add_to_docker_group(username: str) -> dict:
        """Add user to docker group

        Args:
            username: The username to add

        Returns:
            dict with success status and message
        """
        if not UserManager.user_exists(username):
            return {"success": False, "message": f"User '{username}' does not exist"}

        if UserManager.is_in_docker_group(username):
            return {"success": False, "message": f"User '{username}' is already in docker group"}

        result = subprocess.run(
            f"sudo usermod -aG docker {username}",
            shell=True,
            capture_output=True,
            text=True
        )

        if result.returncode == 0:
            return {
                "success": True,
                "message": f"User '{username}' added to docker group. Logout/login required."
            }
        else:
            return {
                "success": False,
                "message": f"Failed to add to docker group: {result.stderr}"
            }

    @staticmethod
    def remove_from_docker_group(username: str) -> dict:
        """Remove user from docker group

        Args:
            username: The username to remove

        Returns:
            dict with success status and message
        """
        if not UserManager.is_in_docker_group(username):
            return {"success": False, "message": f"User '{username}' is not in docker group"}

        result = subprocess.run(
            f"sudo gpasswd -d {username} docker",
            shell=True,
            capture_output=True,
            text=True
        )

        if result.returncode == 0:
            return {
                "success": True,
                "message": f"User '{username}' removed from docker group"
            }
        else:
            return {
                "success": False,
                "message": f"Failed to remove from docker group: {result.stderr}"
            }

    @staticmethod
    def add_user_to_group(username: str = None) -> bool:
        """Add user to infra-users group (requires sudo)"""
        if username is None:
            username = os.environ.get("USER", os.environ.get("USERNAME", ""))

        if not username:
            print("Could not determine username")
            return False

        if UserManager.is_user_in_group(username):
            print(f"User '{username}' is already in '{UserManager.GROUP_NAME}' group")
            return True

        print(f"Adding user '{username}' to '{UserManager.GROUP_NAME}' group (requires sudo)...")
        cmd = f"sudo usermod -aG {UserManager.GROUP_NAME} {username}"
        result = UserManager.run_command(cmd)

        if result is not None or UserManager.is_user_in_group(username):
            print(f"✓ User '{username}' added to '{UserManager.GROUP_NAME}' group")
            print("⚠️  Log out and log back in for changes to take effect")
            return True

        return False

    @staticmethod
    def remove_user_from_group(username: str) -> bool:
        """Remove user from infra-users group (requires sudo)"""
        if not UserManager.is_user_in_group(username):
            print(f"User '{username}' is not in '{UserManager.GROUP_NAME}' group")
            return True

        print(f"Removing user '{username}' from '{UserManager.GROUP_NAME}' group (requires sudo)...")
        # This requires editing /etc/group directly or using gpasswd
        cmd = f"sudo gpasswd -d {username} {UserManager.GROUP_NAME}"
        result = UserManager.run_command(cmd)

        if result is not None:
            return not UserManager.is_user_in_group(username)

        return False

    @staticmethod
    def ensure_current_user_in_group() -> None:
        """Ensure current user is in the group, prompt if not"""
        if not UserManager.group_exists():
            print(f"Group '{UserManager.GROUP_NAME}' does not exist")
            UserManager.create_group()

        if not UserManager.is_user_in_group():
            print(f"Current user is not in '{UserManager.GROUP_NAME}' group")
            UserManager.add_user_to_group()

    @staticmethod
    def get_all_users() -> List[str]:
        """Get list of all system users (with UID >= 1000)"""
        # System users to exclude even if they have high UIDs
        excluded_users = {"nobody", "nogroup"}

        output = UserManager.run_command("getent passwd | cut -d: -f1,3")
        users = []
        for line in output.split("\n"):
            if not line:
                continue
            parts = line.split(":")
            if len(parts) >= 2:
                username, uid = parts[0], parts[1]
                try:
                    if int(uid) >= 1000 and username not in excluded_users:
                        users.append(username)
                except ValueError:
                    continue
        return users

    @staticmethod
    def user_exists(username: str) -> bool:
        """Check if a user exists"""
        return bool(UserManager.run_command(f"id {username} 2>/dev/null"))

    @staticmethod
    def create_user(username: str, create_home: bool = True) -> dict:
        """Create a new system user

        Args:
            username: The username to create
            create_home: Whether to create home directory (system user if False)

        Returns:
            dict with success status and message
        """
        if UserManager.user_exists(username):
            return {"success": False, "message": f"User '{username}' already exists"}

        # Build command
        if create_home:
            # Regular user with home directory
            cmd = f"sudo useradd -m -s /bin/bash {username}"
        else:
            # System user without home directory
            cmd = f"sudo useradd -r -s /usr/sbin/nologin {username}"

        result = subprocess.run(cmd, shell=True, capture_output=True, text=True)

        if result.returncode == 0:
            return {
                "success": True,
                "message": f"User '{username}' created successfully"
            }
        else:
            return {
                "success": False,
                "message": f"Failed to create user: {result.stderr}"
            }

    @staticmethod
    def set_password(username: str, password: str) -> dict:
        """Set password for a user

        Args:
            username: The username
            password: The new password

        Returns:
            dict with success status and message
        """
        if not UserManager.user_exists(username):
            return {"success": False, "message": f"User '{username}' does not exist"}

        # Use chpasswd to set password (reads from stdin)
        try:
            process = subprocess.Popen(
                ["sudo", "chpasswd"],
                stdin=subprocess.PIPE,
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
                text=True
            )
            stdout, stderr = process.communicate(input=f"{username}:{password}\n")

            if process.returncode == 0:
                return {
                    "success": True,
                    "message": f"Password set for '{username}'"
                }
            else:
                return {
                    "success": False,
                    "message": f"Failed to set password: {stderr}"
                }
        except Exception as e:
            return {
                "success": False,
                "message": f"Failed to set password: {e}"
            }

    @staticmethod
    def get_user_home(username: str) -> str:
        """Get the home directory path for a user"""
        result = subprocess.run(
            f"getent passwd {username}",
            shell=True,
            capture_output=True,
            text=True
        )
        if result.returncode == 0 and result.stdout:
            # Format: username:x:uid:gid:comment:home:shell
            parts = result.stdout.strip().split(":")
            if len(parts) >= 6:
                return parts[5]
        return ""

    @staticmethod
    def delete_user(username: str, remove_home: bool = False, force: bool = False) -> dict:
        """Delete a system user

        Args:
            username: The username to delete
            remove_home: Whether to remove user's home directory (CLI only)
            force: Skip home directory check (CLI only with -r flag)

        Returns:
            dict with success status and message
        """
        import getpass

        # Safety checks
        if username == "root":
            return {"success": False, "message": "Cannot delete root user"}

        current_user = getpass.getuser()
        if username == current_user:
            return {"success": False, "message": "Cannot delete your own user account"}

        if not UserManager.user_exists(username):
            return {"success": False, "message": f"User '{username}' does not exist"}

        # Check for running processes
        result = subprocess.run(
            f"pgrep -u {username}",
            shell=True,
            capture_output=True,
            text=True
        )
        if result.returncode == 0:
            return {
                "success": False,
                "message": f"User '{username}' has running processes. Kill them first with: sudo pkill -u {username}"
            }

        # Check if user has a home directory that still exists
        home_dir = UserManager.get_user_home(username)
        if home_dir and os.path.exists(home_dir) and not remove_home:
            return {
                "success": False,
                "message": f"User '{username}' has home directory at {home_dir}. Delete it first or use CLI: infra user delete -r {username}"
            }

        # Build delete command
        if remove_home:
            cmd = f"sudo userdel -r {username}"
        else:
            cmd = f"sudo userdel {username}"

        result = subprocess.run(cmd, shell=True, capture_output=True, text=True)

        if result.returncode == 0:
            return {
                "success": True,
                "message": f"User '{username}' deleted successfully"
            }
        else:
            return {
                "success": False,
                "message": f"Failed to delete user: {result.stderr}"
            }

    @staticmethod
    def can_delete_user(username: str) -> tuple:
        """Check if a user can be deleted from TUI

        Returns:
            tuple of (can_delete: bool, reason: str)
        """
        import getpass

        if username == "root":
            return (False, "Cannot delete root")

        current_user = getpass.getuser()
        if username == current_user:
            return (False, "Cannot delete self")

        if not UserManager.user_exists(username):
            return (False, "User doesn't exist")

        # Check for home directory
        home_dir = UserManager.get_user_home(username)
        if home_dir and os.path.exists(home_dir):
            return (False, f"Has home dir")

        # Check for running processes
        result = subprocess.run(
            f"pgrep -u {username}",
            shell=True,
            capture_output=True,
            text=True
        )
        if result.returncode == 0:
            return (False, "Has processes")

        return (True, "")

    @staticmethod
    def is_sudoer(username: str) -> bool:
        """Check if user is in sudo group"""
        groups = UserManager.run_command(f"groups {username} 2>/dev/null")
        return "sudo" in groups if groups else False

    @staticmethod
    def add_to_sudoers(username: str) -> dict:
        """Add user to sudo group

        Args:
            username: The username to add to sudo group

        Returns:
            dict with success status and message
        """
        if not UserManager.user_exists(username):
            return {"success": False, "message": f"User '{username}' does not exist"}

        if UserManager.is_sudoer(username):
            return {"success": False, "message": f"User '{username}' is already a sudoer"}

        result = subprocess.run(
            f"sudo usermod -aG sudo {username}",
            shell=True,
            capture_output=True,
            text=True
        )

        if result.returncode == 0:
            return {
                "success": True,
                "message": f"User '{username}' added to sudo group"
            }
        else:
            return {
                "success": False,
                "message": f"Failed to add to sudo group: {result.stderr}"
            }

    @staticmethod
    def has_passwordless_sudo(username: str) -> bool:
        """Check if user has passwordless sudo access"""
        # Check the infra-users sudoers file directly for an active NOPASSWD rule
        sudoers_file = "/etc/sudoers.d/infra-users"

        # Check infra-users file first
        result = subprocess.run(
            ["sudo", "cat", sudoers_file],
            capture_output=True,
            text=True
        )
        if result.returncode == 0:
            for line in result.stdout.splitlines():
                stripped = line.strip()
                # Check for uncommented NOPASSWD rule for this user
                if (stripped.startswith(username) and
                    "NOPASSWD" in stripped and
                    not stripped.startswith("#")):
                    return True

        # Also check main sudoers file
        result = subprocess.run(
            ["sudo", "cat", "/etc/sudoers"],
            capture_output=True,
            text=True
        )
        if result.returncode == 0:
            for line in result.stdout.splitlines():
                stripped = line.strip()
                if (stripped.startswith(username) and
                    "NOPASSWD" in stripped and
                    not stripped.startswith("#")):
                    return True

        return False

    @staticmethod
    def set_passwordless_sudo(username: str, enable: bool) -> dict:
        """Enable or disable passwordless sudo for a user

        Args:
            username: The username
            enable: True to enable passwordless sudo, False to disable

        Returns:
            dict with success status and message
        """
        if not UserManager.is_sudoer(username):
            return {"success": False, "message": f"User '{username}' is not in sudo group"}

        sudoers_file = "/etc/sudoers.d/infra-users"

        if enable:
            # Enable passwordless sudo by uncommenting or adding rule in infra-users file
            try:
                # Check if there's a commented rule in infra-users file
                result = subprocess.run(
                    ["sudo", "cat", sudoers_file],
                    capture_output=True,
                    text=True
                )

                if result.returncode == 0:
                    lines = result.stdout.splitlines(keepends=True)

                    new_lines = []
                    modified = False
                    for line in lines:
                        if line.strip().startswith(f"#{username}") and "NOPASSWD" in line:
                            # Uncomment the line
                            new_lines.append(line.lstrip("#"))
                            modified = True
                        else:
                            new_lines.append(line)

                    if modified:
                        with open("/tmp/sudoers_temp", "w") as f:
                            f.writelines(new_lines)

                        subprocess.run(["sudo", "visudo", "-c", "-f", "/tmp/sudoers_temp"], check=True)
                        subprocess.run(["sudo", "cp", "/tmp/sudoers_temp", sudoers_file], check=True)
                        subprocess.run(["sudo", "chown", "root:root", sudoers_file], check=True)
                        subprocess.run(["sudo", "chmod", "440", sudoers_file], check=True)

                        return {"success": True, "message": f"Passwordless sudo enabled for '{username}'"}

                    # Check if user already has an active rule
                    existing_rules = result.stdout
                    if f"{username} ALL=" in existing_rules and not f"#{username} ALL=" in existing_rules:
                        return {"success": False, "message": f"User '{username}' already has passwordless sudo"}

                # No commented rule found, add a new one to infra-users file
                rule = f"{username} ALL=(ALL:ALL) NOPASSWD:ALL\n"

                # Get existing rules (file might not exist yet)
                existing_rules = ""
                if result.returncode == 0:
                    existing_rules = result.stdout

                # Append new rule
                with open("/tmp/sudoers_temp", "w") as f:
                    f.write(existing_rules)
                    f.write(rule)

                # Validate and install
                subprocess.run(["sudo", "visudo", "-c", "-f", "/tmp/sudoers_temp"], check=True)
                subprocess.run(["sudo", "cp", "/tmp/sudoers_temp", sudoers_file], check=True)
                subprocess.run(["sudo", "chown", "root:root", sudoers_file], check=True)
                subprocess.run(["sudo", "chmod", "440", sudoers_file], check=True)

                return {"success": True, "message": f"Passwordless sudo enabled for '{username}'"}
            except Exception as e:
                return {"success": False, "message": f"Failed to enable passwordless sudo: {e}"}
        else:
            # Disable passwordless sudo by commenting out NOPASSWD in the rule
            try:
                # Check and modify main sudoers file first
                main_sudoers = "/etc/sudoers"
                result = subprocess.run(
                    ["sudo", "grep", f"^[^#]*{username}.*NOPASSWD", main_sudoers],
                    capture_output=True,
                    text=True
                )

                if result.returncode == 0:
                    # User has passwordless sudo in main sudoers file
                    # Read the file and comment out the NOPASSWD rule
                    read_result = subprocess.run(
                        ["sudo", "cat", main_sudoers],
                        capture_output=True,
                        text=True,
                        check=True
                    )
                    lines = read_result.stdout.splitlines(keepends=True)

                    new_lines = []
                    for line in lines:
                        stripped = line.strip()
                        if stripped.startswith(username) and "NOPASSWD" in line and not stripped.startswith("#"):
                            # Comment out the line
                            new_lines.append(f"#{line}")
                        else:
                            new_lines.append(line)

                    # Write to temp file and validate
                    with open("/tmp/sudoers_temp", "w") as f:
                        f.writelines(new_lines)

                    subprocess.run(["sudo", "visudo", "-c", "-f", "/tmp/sudoers_temp"], check=True)
                    subprocess.run(["sudo", "cp", "/tmp/sudoers_temp", main_sudoers], check=True)

                    return {"success": True, "message": f"Passwordless sudo disabled for '{username}' (line commented in /etc/sudoers)"}

                # Check infra-users file
                result = subprocess.run(
                    ["sudo", "cat", sudoers_file],
                    capture_output=True,
                    text=True
                )

                if result.returncode == 0:
                    lines = result.stdout.splitlines(keepends=True)

                    new_lines = []
                    modified = False
                    for line in lines:
                        stripped = line.strip()
                        if stripped.startswith(username) and "NOPASSWD" in line and not stripped.startswith("#"):
                            # Comment out the line
                            new_lines.append(f"#{line}")
                            modified = True
                        else:
                            new_lines.append(line)

                    if modified:
                        with open("/tmp/sudoers_temp", "w") as f:
                            f.writelines(new_lines)

                        # Validate and install
                        subprocess.run(["sudo", "visudo", "-c", "-f", "/tmp/sudoers_temp"], check=True)
                        subprocess.run(["sudo", "cp", "/tmp/sudoers_temp", sudoers_file], check=True)
                        subprocess.run(["sudo", "chown", "root:root", sudoers_file], check=True)
                        subprocess.run(["sudo", "chmod", "440", sudoers_file], check=True)

                        return {"success": True, "message": f"Passwordless sudo disabled for '{username}'"}

                return {"success": False, "message": f"No passwordless sudo rule found for '{username}'"}
            except Exception as e:
                return {"success": False, "message": f"Failed to disable passwordless sudo: {e}"}
