#!/bin/python3

import os
import sys
import datetime
import glob
import subprocess
import configparser
from pathlib import Path

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.fix_conf import ThirdConf, FixJar
from UpgradeCheck.fix_security import Security


# ============ 修复结果上报 ============

UPDATE_ID_CONF = '/var/lib/kylin-software-properties/config/updateID.conf'
UPLOAD_STATUS_CODE = 26


def get_update_uuid():
    """从 /var/lib/kylin-software-properties/config/updateID.conf 读取 uuid"""
    if not os.path.exists(UPDATE_ID_CONF):
        return ''
    try:
        config = configparser.ConfigParser()
        config.read(UPDATE_ID_CONF)
        return config.get('update', 'uuid', fallback='')
    except Exception:
        return ''


def get_installed_packages(manifest_dir):
    """从 kpct_install 的 manifest 文件获取已安装的包名

    manifest 每行格式: <deb全路径>|<size>|<mtime>
    deb 文件名格式: <包名>_<版本>_<架构>.deb
    manifest 由 auto_pack.sh 写入，路径: /var/kpct/cache/.kpct_manifest_*
    """
    packages = set()
    if not manifest_dir or not os.path.isdir(manifest_dir):
        return packages
    # 只读最新的一份 manifest
    manifests = sorted(
        glob.glob(os.path.join(manifest_dir, '.kpct_manifest_*')),
        key=lambda f: Path(f).stat().st_mtime,
        reverse=True,
    )
    for manifest in manifests[:1]:
        try:
            with open(manifest, 'r') as f:
                for line in f:
                    line = line.strip()
                    if not line:
                        continue
                    deb_path = line.split('|')[0]
                    deb_name = os.path.basename(deb_path)
                    if '_' in deb_name:
                        pkg = deb_name.split('_')[0]
                    else:
                        pkg = deb_name.replace('.deb', '')
                    if pkg:
                        packages.add(pkg)
        except Exception:
            pass
    return packages


def get_thirdconf_fix_packages(kdb):
    """从 CONFINFO 表获取 ThirdConf 修复涉及的包名"""
    packages = set()
    try:
        res = kdb.select_all('SELECT DISTINCT debname FROM CONFINFO')
        for row in res:
            if row and row[0]:
                packages.add(row[0])
    except Exception:
        pass
    return packages


def build_description(fix_packages, installed_packages):
    """构建修复结果描述

    有包: "pkg1、pkg2修复成功，安全标记完成覆盖"
    无包: "安全打标成功"
    """
    all_packages = fix_packages | installed_packages
    if all_packages:
        return '、'.join(sorted(all_packages)) + '修复成功，安全标记完成覆盖'
    return '安全打标成功'


def upload_upgrade_status(kuc_log, description):
    """通过 systemBus 调用 com.kylin.software.properties.uploadUpgradeStatus 上传修复结果

    入参: string uuid, int statusCode, string description
    失败不影响修复主流程
    """
    uuid = get_update_uuid()
    try:
        cmd = [
            'dbus-send', '--system', '--print-reply',
            '--dest=com.kylin.software.properties',
            '/com/kylin/software/properties',
            'com.kylin.software.properties.interface.uploadUpgradeStatus',
            'string:{}'.format(uuid),
            'int32:{}'.format(UPLOAD_STATUS_CODE),
            'string:{}'.format(description),
        ]
        result = subprocess.run(
            cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=10)
        if result.returncode == 0:
            kuc_log.info('上传修复结果成功: uuid={}, statusCode={}, desc={}'.format(
                uuid, UPLOAD_STATUS_CODE, description))
        else:
            kuc_log.error('上传修复结果失败: {}'.format(
                result.stderr.decode('utf-8', errors='replace')))
    except Exception as e:
        kuc_log.error('上传修复结果异常: {}'.format(e))


def main():
    start_time = datetime.datetime.now()

    kuc_log = Log().getlog()
    kuc_log.info('===== Upgrade升级修复检测: 扫描结果收集开始')
    kpct_conf = KpctConf(kuc_log)
    save_path = kpct_conf.save_path

    report_path = ""

    fix_list = [
        ThirdConf,
        FixJar,
        Security
    ]

# 搜索所有数据库文件
    db_files = glob.glob("/home/*/.kpct/UpgradeCheck/collect_information.db")
    
    if not db_files:
        print("未找到collect_information.db文件")
        exit(1)
    
    # 找到最新的文件
    db_path = max(db_files, key=lambda f: Path(f).stat().st_mtime)
    kuc_log.info(db_path)

    # current_user = os.getlogin()
    # db_path = '/home/{}/.kpct/UpgradeCheck/{}'.format(current_user, 'collect_information.db')

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

    if not os.path.exists(db_path):
        kuc_log.error('===== Upgrade升级修复: 扫描结果报告不存在，执行安全执行修复')
        fix_list = [Security]


    if not os.path.exists(db_path):
        kuc_log.error('===== Upgrade升级修复: 数据库文件不存在，停止修复')
        # 数据库不存在时仍上报: 无包修复,仅安全打标
        upload_upgrade_status(kuc_log, build_description(set(), set()))
        return
    else:
        kdb = KylinUpGradeDataBase(db_path)
        for fix in fix_list:
            obj = fix(kuc_log, kdb)
            obj.run()

        # 收集 ThirdConf 修复涉及的包名
        fix_packages = get_thirdconf_fix_packages(kdb)
        kdb.close()

    # 收集 kpct_install 安装的包名 (manifest 由 auto_pack.sh 写到 /var/kpct/cache/)
    # 优先从 /var/kpct/cache/ 读取;兜底从用户家目录读取
    manifest_dir = '/var/kpct/cache'
    installed_packages = get_installed_packages(manifest_dir)
    if not installed_packages:
        # 兜底: 旧版本 auto_pack 可能写到用户家目录
        home_dir = str(Path(db_path).parents[2])
        manifest_dir = os.path.join(home_dir, '.update-cache')
        installed_packages = get_installed_packages(manifest_dir)

    # 上报修复结果
    description = build_description(fix_packages, installed_packages)
    upload_upgrade_status(kuc_log, description)

    end_time = datetime.datetime.now()
    kuc_log.info("===== Upgrade升级后修复: 信息检测结束")
    kuc_log.info("===== 修复运行时间：{}s".format((end_time - start_time).total_seconds()))

if __name__ == "__main__":
    main()
