import os
import socket
import subprocess
import sys
from typing import IO

from .MachineInterface import MachineInterface


def _system_env() -> dict[str, str]:
    """
    Build an environment for child processes that ignores any active Python
    virtualenv. Tools like `univention-app` shell out to the system Python and
    expect the system trust store; inheriting venv vars makes them load the
    venv's site-packages and certifi bundle instead, which fails to verify
    the UCS self-signed CA.
    """
    env = os.environ.copy()
    venv_bins: list[str] = []

    venv = env.pop('VIRTUAL_ENV', None)
    if venv:
        venv_bins.append(os.path.join(venv, 'bin'))
    if sys.prefix != sys.base_prefix:
        venv_bins.append(os.path.join(sys.prefix, 'bin'))

    env.pop('PYTHONHOME', None)
    env.pop('PYTHONPATH', None)

    if venv_bins:
        normalized_venv_bins = {os.path.normpath(b) for b in venv_bins}
        path_parts = [
            p for p in env.get('PATH', '').split(os.pathsep)
            if p and os.path.normpath(p) not in normalized_venv_bins
        ]
        env['PATH'] = os.pathsep.join(path_parts)

    return env


class LocalMachine(MachineInterface):
    def check_if_file_exists(self, file_path: str) -> bool:
        return os.path.isfile(file_path)

    def read_file(self, file_path: str) -> bytes:
        if not os.path.isfile(file_path):
            raise FileNotFoundError

        data = bytes()
        with open(file_path, 'rb') as file:
            data = file.read()
        return data

    def write_file(self, file_path: str, data: bytes) -> None:
        with open(file_path, 'wb') as file:
            file.write(data)

    def delete(self, file_path: str):
        if os.path.isfile(file_path):
            os.remove(file_path)
        elif os.path.isdir(file_path):
            os.rmdir(file_path)

    def move(self, source_file: str, destination_file: str):
        os.rename(source_file, destination_file)

    def mkdir(self, dir_path: str) -> None:
        os.makedirs(dir_path, exist_ok=True)

    def execute_shell_command(self, command: str, *args: str) ->  tuple[str, str, int]:
        argv = list(args)
        argv.insert(0, command)
        result = subprocess.run(argv, capture_output=True, env=_system_env())
        output = result.stdout.decode()
        error = result.stderr.decode()
        result_code = result.returncode

        return output, error, result_code

    def execute_shell_command_live(self, command: str, *args: str) ->  tuple[IO, IO, IO]:
        argv = list(args)
        argv.insert(0, command)
        process = subprocess.Popen(
            argv,
            stdin=subprocess.PIPE,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            env=_system_env(),
        )

        return process.stdin, process.stdout, process.stderr

    def get_hostname(self) -> str:
        return socket.getfqdn()

    def get_hostname_short(self) -> str:
        return socket.gethostname().split('.')[0]