from __future__ import annotations

import os
import re
import subprocess
from logger import get_logger

log = get_logger("actions.sftp")


def user_exists(username: str) -> bool:
    """Check if a system user exists using pwd or /etc/passwd fallback."""
    try:
        import pwd
        pwd.getpwnam(username)
        return True
    except KeyError:
        return False
    except ImportError:
        # Fallback for Windows development environment
        if os.path.exists("/etc/passwd"):
            try:
                with open("/etc/passwd", "r", encoding="utf-8") as f:
                    for line in f:
                        parts = line.strip().split(":")
                        if parts and parts[0] == username:
                            return True
            except Exception:
                pass
        return False


def _verify_safe_path(user_path: str) -> str:
    """Resolve and verify that the path is strictly within the allowed web root base directory."""
    if not user_path:
        raise ValueError("home_directory is required")
        
    dev_home = os.environ.get("WOLFPANEL_DEV_HOME")
    if dev_home:
        base_path = os.path.realpath(os.path.join(dev_home, "var", "www"))
    else:
        base_path = os.path.realpath("/var/www")
        
    resolved_path = os.path.realpath(user_path)
    
    # Check if the resolved path is outside the base directory
    if resolved_path != base_path and not resolved_path.startswith(base_path + os.sep):
        # Fallback check for Unix path style in Windows test environments
        normalized_resolved = resolved_path.replace("\\", "/")
        normalized_base = base_path.replace("\\", "/")
        if len(normalized_resolved) > 1 and normalized_resolved[1] == ":":
            normalized_resolved = normalized_resolved[2:]
        if len(normalized_base) > 1 and normalized_base[1] == ":":
            normalized_base = normalized_base[2:]
            
        if normalized_resolved != normalized_base and not normalized_resolved.startswith(normalized_base + "/"):
            raise PermissionError(f"Access denied: Path is outside of allowed base directory ({resolved_path})")
            
    if os.name == "nt" and user_path.startswith("/"):
        res_str = resolved_path
        if len(res_str) > 1 and res_str[1] == ":":
            res_str = res_str[2:]
        return res_str.replace("\\", "/")
        
    return resolved_path


def handle_sftp_create(payload: dict) -> dict:
    """Create a new SFTP user with a home directory and group www-data, and assign password."""
    try:
        username_suffix = payload.get("username_suffix")
        password = payload.get("password")
        home_directory = payload.get("home_directory")

        if not username_suffix or not password or not home_directory:
            raise ValueError("username_suffix, password, and home_directory are required")

        # Sanitize suffix: alphanumeric + underscores, max 32 chars
        suffix_sanitized = re.sub(r'[^a-zA-Z0-9_]', '', str(username_suffix))[:32]
        if not suffix_sanitized:
            raise ValueError("Invalid or empty username_suffix")

        safe_home_directory = _verify_safe_path(home_directory)
        username = f"wolf_sftp_{suffix_sanitized}"
        log.info("Attempting to create SFTP user: %s (home: %s)", username, safe_home_directory)

        if user_exists(username):
            raise ValueError(f"User {username} already exists")

        # Run useradd command
        cmd_useradd = [
            "useradd",
            "-m",
            "-d", safe_home_directory,
            "-s", "/usr/sbin/nologin",
            "-g", "www-data",
            username
        ]
        res = subprocess.run(cmd_useradd, capture_output=True, text=True, check=False)
        if res.returncode != 0:
            raise OSError(f"useradd failed: {res.stderr.strip()}")

        # Run chpasswd command securely using input pipe (password is NOT logged)
        res = subprocess.run(
            ["chpasswd"],
            input=f"{username}:{password}",
            capture_output=True,
            text=True,
            check=False
        )
        if res.returncode != 0:
            raise OSError(f"chpasswd failed: {res.stderr.strip()}")

        # Update home directory permissions
        res = subprocess.run(["chmod", "750", safe_home_directory], capture_output=True, text=True, check=False)
        if res.returncode != 0:
            raise OSError(f"chmod failed: {res.stderr.strip()}")

        res = subprocess.run(["chown", f"{username}:www-data", safe_home_directory], capture_output=True, text=True, check=False)

        if res.returncode != 0:
            raise OSError(f"chown failed: {res.stderr.strip()}")

        log.info("SFTP user %s created successfully", username)
        return {
            "success": True,
            "message": f"SFTP user {username} created successfully",
            "username": username
        }

    except Exception as exc:
        log.error("SFTP creation failed (password hidden): %s", str(exc).replace(payload.get("password", "____"), "____"))
        return {
            "success": False,
            "error": str(exc),
        }


def handle_sftp_delete(payload: dict) -> dict:
    """Delete an SFTP user and their home directory."""
    try:
        username = payload.get("username", "")
        if not username.startswith("wolf_sftp_"):
            raise ValueError("Username must start with 'wolf_sftp_'")

        log.info("Attempting to delete SFTP user: %s", username)

        if not user_exists(username):
            raise ValueError(f"User {username} does not exist")

        # Run userdel -r command
        res = subprocess.run(["userdel", "-r", username], capture_output=True, text=True, check=False)
        if res.returncode != 0:
            raise OSError(f"userdel failed: {res.stderr.strip()}")

        log.info("SFTP user %s deleted successfully", username)
        return {
            "success": True,
            "message": f"SFTP user {username} deleted successfully",
            "username": username
        }

    except Exception as exc:
        log.error("SFTP deletion failed: %s", exc)
        return {
            "success": False,
            "error": str(exc),
        }


def handle_sftp_reset_password(payload: dict) -> dict:
    """Reset the password for an SFTP user."""
    try:
        username = payload.get("username", "")
        new_password = payload.get("new_password")

        if not username or not new_password:
            raise ValueError("username and new_password are required")

        if not username.startswith("wolf_sftp_"):
            raise ValueError("Username must start with 'wolf_sftp_'")

        log.info("Attempting to reset password for SFTP user: %s", username)

        if not user_exists(username):
            raise ValueError(f"User {username} does not exist")

        # Run chpasswd command securely using input pipe (password is NOT logged)
        res = subprocess.run(
            ["chpasswd"],
            input=f"{username}:{new_password}",
            capture_output=True,
            text=True,
            check=False
        )
        if res.returncode != 0:
            raise OSError(f"chpasswd failed: {res.stderr.strip()}")

        log.info("Password for SFTP user %s reset successfully", username)
        return {
            "success": True,
            "message": f"Password for SFTP user {username} reset successfully",
            "username": username
        }

    except Exception as exc:
        log.error("SFTP password reset failed (password hidden): %s", str(exc).replace(payload.get("new_password", "____"), "____"))
        return {
            "success": False,
            "error": str(exc),
        }
