#!/usr/bin/python3
import os
import time
import json
import subprocess
import datetime

from pathlib import Path
from threading import Thread, Event
from pydbus import SessionBus
from pydbus.generic import signal
from gi.repository import GLib

import sys
for root, dirs, _ in os.walk("/usr/lib/python3/dist-packages"):
    for dir_name in dirs:
        if dir_name.startswith("UpgradeCheck"):
            sys.path.append(os.path.join(root, dir_name))
        if dir_name.startswith("DependCheck"):
            sys.path.append(os.path.join(root, dir_name))

from UpgradeCheck.util_conf import KpctConf
from UpgradeCheck.util_deb import KpctDeb
from UpgradeCheck.util_log import Log
from UpgradeCheck.util_dbus import ExternalController
from UpgradeCheck.util_database import KylinUpGradeDataBase
from UpgradeCheck.collect_sys_info import SysInfo, DbusInfo
from UpgradeCheck.collect_deb_info import DebInfo, NewOsDebDepend, LibInDirInfo, BaseCollect
from UpgradeCheck.collect_file_info import (ElfInfo, ConfInfo, PermissionInfo, ServiceInfo, ShellInfo,
                                            HighPermissionInfo, DesktopInfo, QtInfo, DbusListInfo,
                                            SystemdStrongDependInfo, PythonImportInfo,JavaJarInfo)

from UpgradeCheck.compare_lib import (SelfIncludeCompare, DiffSymCompare, DiffPreupgradeCompare, DiffLddCompare, SysLibInDeb, QtInDebCompare,
                                      DtSysLibInDeb, BaseCompare, DlopenCompare)
from UpgradeCheck.compare_file import (ConfFileCompare, PermissionCompare, DesktopCompare, ServiceFileCompare,
                                       MissingElfTarCompare, DbusUnderControl,PythonImportCompare)

from UpgradeCheck.util_common import result_path

collect_list_for_dbus = [
    SysInfo,
    DebInfo,
    DesktopInfo,
    ElfInfo,
    ShellInfo,
    ConfInfo,
    ServiceInfo,
    DbusInfo,
    PermissionInfo,
    HighPermissionInfo,
    QtInfo,
    NewOsDebDepend,
    SystemdStrongDependInfo,
    PythonImportInfo,
    JavaJarInfo
]

compare_list_for_dbus = [
    PermissionCompare,
    ConfFileCompare,
    # ServiceFileCompare,
    SysLibInDeb,
    SelfIncludeCompare,
    DiffSymCompare,
    DiffLddCompare,
    QtInDebCompare,
    DtSysLibInDeb,
    PythonImportCompare
    # DbusUnderControl
]

class CustomInt(int):
    def __init__(self, value):
        if not isinstance(value, int):
            raise ValueError('请输入整数')
        self._value = value

    def __add__(self, other):
        if (self._value + other) >= 100:
            return CustomInt(99)
        else:
            return CustomInt(self._value + other)


progress_percect = CustomInt(0)
stop_event = Event()


def symbol_init():
    # BaseCompare.symbol_db_path = '/opt/kpct/UpgradeCheck/symbols.db'
    # packages_path = "/var/cache/kylin-system-updater/will_update_pkgs.json"
    # if os.path.exists(packages_path):
    #     with open(packages_path) as f:
    #         content = json.loads(f.read())
    #     BaseCompare.name_version = content["pkgs_upgrade"]
    deb_json_dir = '/var/cache/kpct/symbol'
    json_files = Path(deb_json_dir).glob("*.json")
    # {deb_name:{version:"v1", lib1:[s1, s2, s3...], lib2}}
    # 包名没用
    # {lib1: "s1\ns2\n...", lib2: "s1\ns2\n..."}
    sym_dict = {}
    for file in json_files:
        base_name = os.path.basename(file.as_posix())
        # name = base_name.split('_')[0]
        # version = base_name.split('_')[1].replace('%3', ':')
        with open(file.as_posix(), 'r') as f:
            # {"libname": "sym1\nsym2\n",...}
            content = json.loads(f.read())
        if not content:
            continue
        for elf, syms in content:
            sym_dict[elf] = syms
        # sym_dict[name]["version"] = version

    python_import_json = '/var/cache/kpct/python'
    py_json_files = Path(python_import_json).glob("*.json")
    pyi_dict = {}
    pyfile_attr_dict = {}
    for file in py_json_files:
        base_name = os.path.basename(file.as_posix())
        name = base_name.split('_')[0]
        # version = base_name.split('_')[1].replace('%3', ':')
        with open(file.as_posix(), 'r') as f:
            # {"libname": "sym1\nsym2\n",...}
            content = json.loads(f.read())
        if not content:
            continue
        pyi_dict[name] = list(content.keys())
        pyfile_attr_dict = {**pyfile_attr_dict, **content}

    BaseCompare.deb_json_dict = sym_dict
    BaseCompare.python_json_dict = pyi_dict
    BaseCompare.pyfile_json_dict = pyfile_attr_dict


def collect_for_dbus():
    global progress_percect, stop_event
    progress_percect = CustomInt(0)
    from UpgradeCheck.util_common import result_path
    start_time = datetime.datetime.now()
    kuc_log = Log().getlog()

    kpct_deb = KpctDeb(kuc_log, third_app_flag=True)
    BaseCollect.deb_name = kpct_deb.deb_name
    BaseCollect.deb_dict = kpct_deb.deb_dict

    kuc_process = ExternalController()
    if not os.path.exists(result_path):
        os.makedirs(result_path)
    db_path = '{}/{}'.format(result_path, "collect_information.db")
    kdb = KylinUpGradeDataBase.create(db_path)

    kuc_process.send_progress_signal(progress_percect)

    for collect_check in collect_list_for_dbus:
        if stop_event.is_set():
            kuc_log.info("===== Upgrade升级检测: 信息收集被用户停止")
            kdb.close()
            return False
        if issubclass(collect_check, ElfInfo):
            obj = collect_check(full_scan=False,log=kuc_log, database=kdb, kuc_process=kuc_process, progress_percect=progress_percect)
        else:
            obj = collect_check(kuc_log, kdb)
        obj.run()
        if stop_event.is_set():
            kuc_log.info("===== Upgrade升级检测: 信息收集被用户停止")
            kdb.close()
            return False
        if issubclass(collect_check, ElfInfo):
            progress_percect = obj.progress_percect + 4
        else:
            progress_percect += 4
        kuc_process.send_progress_signal(progress_percect)
    kdb.close()
    end_time = datetime.datetime.now()
    kuc_log.info("===== Upgrade升级检测: 信息收集结束")
    kuc_log.info("===== Upgrade信息收集时间：{}s".format((end_time - start_time).total_seconds()))
    return True


def compare_for_dbus():
    global progress_percect, stop_event
    start_time = datetime.datetime.now()
    symbol_init()
    kuc_log = Log().getlog()
    kuc_log.info('===== Upgrade升级检测: 信息检测开始')
    db_path = '{}/{}'.format(result_path, 'collect_information.db')
    kuc_process = ExternalController()

    if not os.path.exists(result_path):
        os.makedirs(result_path)

    if not os.path.exists(db_path):
        kuc_log.error('===== Upgrade升级检测: 数据库文件不存在，请重新运行collect后再试')
    else:
        kdb = KylinUpGradeDataBase(db_path)
        for compare in compare_list_for_dbus:
            if stop_event.is_set():
                kuc_log.info("===== Upgrade升级检测: 信息检测被用户停止")
                kdb.close()
                return
            obj = compare(kuc_log, kdb)
            obj.run()
            if stop_event.is_set():
                kuc_log.info("===== Upgrade升级检测: 信息检测被用户停止")
                kdb.close()
                return
            progress_percect += 4
            kuc_process.send_progress_signal(progress_percect)
        kdb.close()

    end_time = datetime.datetime.now()
    kuc_log.info("===== 扫描运行时间：{}s".format((end_time - start_time).total_seconds()))

    from UpgradeCheck.report import BaseInfo
    
    # 写 enablePackages / disablePackages
    # 先计算 disable 集合，写 enablePackages 时排除与 disablePackages 同名的包
    # 例如: enable={a,b}, disable={b,c} → 写入 enable={a}, disable={b,c}
    disable_set = set(obj.unfix_deb_set)
    enable_set = set(obj.return_deb_set) - disable_set
    with open("{}/{}".format(result_path, "enablePackages"), 'w') as f1:
        # 每行一个包名（纯文本格式），便于 shell 端（auto_pack.sh）直接按行解析
        for pkg in sorted(enable_set):
            f1.write("{}\n".format(pkg))
    with open("{}/{}".format(result_path, "disablePackages"), 'w') as f2:
        for pkg in sorted(disable_set):
            f2.write("{}\n".format(pkg))
    base_report = BaseInfo(obj.compare_result, result_path)
    base_report.create_report()
    kuc_log.info("===== Upgrade报告生成完毕")

    end_time = datetime.datetime.now()
    kuc_log.info("===== Upgrade升级检测: 信息检测结束")
    kuc_log.info("===== Upgrade信息检测时间：{}s".format((end_time - start_time).total_seconds()))
    kuc_process.send_progress_signal(100)


class MyDBusService(object):
    """
    <node>
        <interface name="org.kpct.service">
            <method name="KpctRun">
            </method>
            <method name="KpctStop">
                <arg type="b" name="success" direction="out"/>
            </method>
            <method name="GetStatus">
                <arg type="b" name="running" direction="out"/>
            </method>
            <signal name="ProgressChanged">
                <arg type="i" name="progress"/>
            </signal>
            <signal name="ResultReady">
                <arg type="i" name="errorCode"/>
                <arg type="as" name="enablePackages"/>
                <arg type="as" name="disablePackages"/>
            </signal>
            <method name="EmitProgress">
                <arg type="i" name="progress" direction="in"/>
            </method>
        </interface>
    </node>
    """
    ProgressChanged = signal()
    ResultReady = signal()
    running=False

    @staticmethod
    def _load_pkg_list(path):
        """读取 enablePackages / disablePackages 文件（每行一个包名）"""
        result = []
        try:
            with open(path, 'r') as f:
                for line in f:
                    name = line.strip()
                    if name:
                        result.append(name)
        except Exception:
            pass
        return result
    disablePackages = []
    _thread_kpct = None

    def kpct_run(self):
        result = collect_for_dbus()
        if result:
            compare_for_dbus()

    def GetStatus(self):
        return self.running

    def KpctStop(self):
        """
        停止运行中的collect过程。
        返回 True 表示成功发起停止请求，False 表示当前没有运行中的任务。

        """
        if not self.running:
            return False
        stop_event.set()
        self.running = False
        self.ProgressChanged(0)
        self.ResultReady(-2, [], [])
        print("已发送停止信号")
        return True

    def KpctRun(self):
        """
        一个示例方法，模拟执行某些任务并发送信号。
        """
        try:
            if (self.running == False):
                stop_event.clear()
                self.running=True
                self._thread_kpct = Thread(target=self.kpct_run, daemon=True)
                self._thread_kpct.start()
            else:
                print("进程运行中")
        except Exception as e:
            self.running=False
            self.ResultReady(-1, [], [])

    def EmitProgress(self, progress):
        if stop_event.is_set():
            return
        self.ProgressChanged(progress)
        if progress == 100:
            enablePackages = self._load_pkg_list("{}/{}".format(result_path, "enablePackages"))
            disable_content = self._load_pkg_list("{}/{}".format(result_path, "disablePackages"))
            result = "任务已完成！"
            self.disablePackages = disable_content
            # enablePackages = ["wechat-beta","wemeet"]
            # disablePackages = ["mtxx", "cn.lanxin"]
            if len(enablePackages) == 0:
                if len(self.disablePackages) > 0 :
                    self.running=False
                    self.ProgressChanged(100)
                    self.ResultReady(101, [], self.disablePackages)
                else:
                    self.running=False
                    self.ProgressChanged(100)
                    self.ResultReady(100, [], self.disablePackages)
            else:
                self.running=False
                self.ResultReady(101, [], self.disablePackages)
                # 打包动作已迁移到 auto_pack.sh，此处不再调用 packer dbus
                # enablePackages / disablePackages 文件保留，由 auto_pack.sh 消费
                print("EmitProgress(100): 已写 enablePackages/disablePackages，等待 auto_pack.sh 消费")
        if progress == 120:
            enablePackages = self._load_pkg_list("{}/{}".format(result_path, "enablePackages"))
            disable_content = self._load_pkg_list("{}/{}".format(result_path, "disablePackages"))
            result = "任务已完成！"
            self.disablePackages = disable_content
            # enablePackages = ["wechat-beta","wemeet"]
            # disablePackages = ["mtxx", "cn.lanxin"]
            if len(enablePackages) > 0:
                # 打包动作已迁移到 auto_pack.sh，此处不再调用 packer dbus
                print("EmitProgress(120): 已写 enablePackages/disablePackages，等待 auto_pack.sh 消费")
            # enablePackages / disablePackages 文件保留，由 auto_pack.sh 消费

if __name__ == "__main__":
    # 获取会话总线
    bus = SessionBus()

    # 创建服务实例
    service = MyDBusService()

    # 注册服务
    bus.publish("org.kpct.service", service)

    # 运行主循环
    loop = GLib.MainLoop()
    print("D-Bus 服务已启动，路径为 'org.kpct.service'")
    loop.run()
