import dbus
import dbus.service
from common.utils import Overlay, HostMessage
from common.log import Log
import threading
from pathlib import Path
import logging
import psutil
import subprocess
import os

# 使用 GLib 主循环

class FixedLog:
    _handlers = {}

    def __init__(self, file_path):
        self.logger = logging.getLogger(file_path)
        self.logger.setLevel(logging.INFO)
        
        if file_path not in FixedLog._handlers:
            handler = logging.FileHandler(file_path)
            formatter = logging.Formatter('%(asctime)s - %(message)s')
            handler.setFormatter(formatter)
            self.logger.addHandler(handler)
            FixedLog._handlers[file_path] = handler

    def info(self, msg):
        self.logger.info(msg)

    def error(self, msg):
        self.logger.error(msg)

    def dbus_signal_output(self, token, line):
        self.kareStandardLogUpdate(token, line)

    def dbus_signal_error(self, token, line):
        self.kareErrorLogUpdate(token, line)

    def dbus_signal_finished(self, token, stdout, stderr):
        self.kareLogFinished(token, stdout, stderr)


class KareAgent(dbus.service.Object, Overlay, HostMessage):
    def __init__(self):
        self.log = Log("/var/log/kare/kare-run.log")
        bus = dbus.SystemBus()
        self._log_cache = {}
        self._running_processes = {}
        bus_name = dbus.service.BusName('com.kylin.kareAgent', bus=bus)
        super().__init__(bus_name, '/com/kylin/kareAgent')

    @dbus.service.method('com.kylin.kareAgent', in_signature='ss', out_signature='')  
    def run(self, cmd, package_name):
        self.log.info("dbus run cmd: {} package_name: {}".format(cmd, package_name))
        t1 = threading.Thread(target=self.run_command_realtime, args=(cmd, self.container_logger(package_name),), daemon=True)
        t1.start()

    @dbus.service.method('com.kylin.kareAgent', in_signature='sss', out_signature='')
    def run_command_line(self, cmd, package_name, token):
        self.log.info(f"运行命令: {cmd} (包名: {package_name}, token: {token})")
        self._running_processes[token] = -1
        t1 = threading.Thread(
            target=self.run_command_line_realtime,
            args=(cmd, self, token, self.container_logger(package_name)), 
            daemon=True
        )
        t1.start()
    @dbus.service.method('com.kylin.kareAgent', in_signature='sshhhhh', out_signature='')
    def run_cups_filter(self, cmd, package_name, stdin_fd, stdout_fd, stderr_fd, back_fd, side_fd):
        def preexec_dup():
            os.dup2(back_fd.take(), 3)
            os.dup2(side_fd.take(), 4)
        def _run(cmd, package_name, stdin_fd, stdout_fd, stderr_fd, back_fd, side_fd):
            try:
                stdin = os.fdopen(stdin_fd.take(), 'rb')
                stdout = os.fdopen(stdout_fd.take(), 'wb')
                stderr = os.fdopen(stderr_fd.take(), 'wb')
                process = subprocess.Popen(
                    cmd,
                    stdin=stdin,
                    stdout=stdout,
                    stderr=stderr,
                    preexec_fn=preexec_dup,
                    pass_fds=(3, 4),
                    shell=True
                )
                exit_code = process.wait() 
            except Exception as e:
                self.log.info("{e}")
        self.log.info("dbus run cmd: {} package_name: {}".format(cmd, package_name))
        t1 = threading.Thread(
            target=_run,
            args=(cmd, package_name, stdin_fd, stdout_fd, stderr_fd, back_fd, side_fd), 
            daemon=True
        )
        t1.start()
    @dbus.service.signal('com.kylin.kareAgent', signature='ss')
    def kareStandardLogUpdate(self, token, line):
        """D-Bus 信号：标准输出更新"""
        pass

    @dbus.service.signal('com.kylin.kareAgent', signature='ss')
    def kareErrorLogUpdate(self, token, line):
        """D-Bus 信号：错误输出更新"""
        pass

    @dbus.service.signal('com.kylin.kareAgent', signature='sss')
    def kareLogFinished(self, token, stdout, stderr):
        """D-Bus 信号：命令执行结束"""
        pass
    
    @dbus.service.method('com.kylin.kareAgent', in_signature='ass', out_signature='')
    def mount_overlay(self, base_dirs, package_path):
        super().mount_overlay(base_dirs, package_path)

    @dbus.service.method('com.kylin.kareAgent', in_signature='ss', out_signature='')
    def packager_version_replace(self, package, version):
        package_info = self.get_config_json("/opt/kare-applications/config/install.json", package)
        package_info["version"] = version
        self.set_config_json("/opt/kare-applications/config/install.json", package, package_info)

    def container_logger(self, package_name):
        try:
            user = self.get_user_by_login1[1]
        except Exception as e:
            user = None
        if user is None:
            self.log.error("获取当前用户失败")
            return self.log
        log_path =f"/home/{user}/.kare/log/{package_name}.log"
        Path(log_path).parent.mkdir(parents=True, exist_ok=True)
        log = FixedLog(log_path)
        self._log_cache[package_name] = log
        return log
    
    @dbus.service.method('com.kylin.kareAgent', in_signature='s', out_signature='i')
    def killApplication(self, token):
        self.log.info(f"尝试终止应用: token={token}")

        if token not in self._running_processes:
            self.log.error(f"未找到与 token={token} 关联的进程")
            return 0

        pid = self._running_processes[token]
        self.log.info(f"准备终止进程树: PID={pid}")

        try:
            parent = psutil.Process(pid)
            for child in parent.children(recursive=True):  # 杀掉所有子进程
                child.kill()
            parent.kill()
            self.log.info(f"成功终止进程树: PID={pid}")
            return 0
        except psutil.NoSuchProcess:
            self.log.warn(f"进程已不存在: PID={pid}")
            return 0
        except Exception as e:
            self.log.error(f"终止进程失败: {e}", exc_info=True)
            return -1