#ifndef KMPACKAGEMANAGER_H
#define KMPACKAGEMANAGER_H

#include <dbus/dbus.h>
#include <sys/stat.h> // 包含 chmod 函数的头文件

#include <cctype>     // 包含 isupper 函数
#include <cstdlib>    // 用于 std::system 函数
#include <functional> // 进度条函数
#include <initializer_list>
#include <iomanip> // For std::fixed and std::setprecision
#include <set>
#include <sstream>
#include <stack>
#include <unordered_map>
#include <unordered_set>
#include <vector>

#include "common/KMFormatter.h"
#include "common/KMEnv.h"
#include "common/KMError.h"
#include "common/KMConfig.h"
#include "common/KMUtil.h"
#include "common/KMCurl.h"
#include "common/KMOSTreeHandler.h"
#include "common/KMParseSummaryJson.h"
#include "common/KMInfoJson.h"

using namespace std;

#define BASE_REOMTE "kaiming-repo"

typedef struct _KMPMProgressStatus
{
    string refId;
    int progress;
    string speed;
    int timeout;
} KMPMProgressStatus;

typedef function<void(std::string ProgressStatus)> KMPMProgressCallBack;


// 任务类型定义
enum TaskType
{
    TASK_TYPE_INSTALL = 0,          // 安装
    TASK_TYPE_UNINSTALL = (1 << 0), // 卸载
    TASK_TYPE_UPDATE = (1 << 1),    // 更新
    TASK_TYPE_REPAIR = (1 << 2),     // 修复
    TASK_TYPE_SEARCH = (1 << 3)     //查询
};

/**
 * @brief 从用户传来的命令行参数
 * 
 */
typedef struct PackageManagerOptions
{
    bool assumeYes = false;       // 用于自动执行操作, false 表示不自动执行操作，true 表示自动执行操作
    string arch;                  // 用于指定架构
    std::string relativeRepoPath; // 相对仓库路径
    bool isPrint = true;           //是否打印信息
    bool unusedYes = false;        // 默认不卸载runtime及base
    bool deletedataYes= false;     // 默认不删除应用数据
} PackageManagerOptions;

/**
 * @brief 统一包管理
 * 
 * 将安装、卸载、更新、修复等功能进行统一处理
 * 
 */
class KMPackageManager
{
public:
    KMPackageManager();
    ~KMPackageManager();
    KMPackageManager(const KMPackageManager &) = delete;
    KMPackageManager(KMPackageManager &&) = delete;
    auto operator=(const KMPackageManager &) -> KMPackageManager & = delete;
    auto operator=(KMPackageManager &&) -> KMPackageManager & = delete;

public:

    /**
     * @brief 用于分发安装、卸载、更新、修复等任务
     * 
     * @param taskType 任务类型
     * @param vectorIds 解析的 ref 列表
     * @return int 任务执行返回
     */
    int processTask(TaskType taskType, const vector<string>& vectorIds, PackageManagerOptions pmOptions);

    /**
     * @brief 安装在线包
     * 
     * @return int 执行返回
     */
    int install(const vector<string>& vectorIds, PackageManagerOptions pmOptions);

    /**
     * @brief 给软件商店调用的api
     *
     * @param name 开明包名，如org.kde.kclock
     * @param version 开明版本号，这里实际上是ostree
     * branch版本，暂未细化到具体子版本。空代表最新版本，如"master"
     * @param installCallback 进度回调函数
     * @param error 是否报错
     * @return true 执行成功
     * @return false 执行失败
     */
    int installSoftwareCenter(string name, string version, int &error, KMPMProgressCallBack installCallback);

    /**
     * @brief 安装离线包
     * 
     * 离线包格式为 .ok, .uab, .layer
     * 
     * @return int 
     */
    int installFromFile();

    /**
     * @brief 兼容kylin ok 离线包
     * 
     * @return int 
     */
    int installFromOK();

    /**
     * @brief 兼容linglong UAB 离线包
     * 
     * @return int 
     */
    int installFromUAB();

    /**
     * @brief 兼容linglong Layer 离线包
     * 
     * @return int 
     */
    int installFromLayer();

     /**
     * @brief 卸载软件包
     * 
     * @param vectorIds 包含待卸载软件包的ID列表
     * @param pmOptions 卸载时的选项参数
     * @return int 返回卸载操作的结果，成功为0
     */
    int uninstall(const vector<string>& vectorIds, PackageManagerOptions pmOptions);

    /**
     * @brief 查找目标应用或运行时的依赖项，并将其添加到待卸载列表中
     * 
     * @param targetId 目标应用、运行时或base的ID
     * @param perUninstallList 待卸载项列表，用于存储需要卸载的ID
     */
    void findDependencies(const std::string &targetId, std::vector<std::string> &perUninstallList);

    /**
     * @brief 加载所有info.json文件，并返回其信息映射
     * 
     * @return std::unordered_map<std::string, KMInfoJson> 包含所有info.json文件信息的映射
     */
    std::unordered_map<std::string, KMInfoJson> loadAllInfoJsonFiles();

    /**
     * @brief 打印待卸载的软件包列表
     * 
     * @param uninstallId 待卸载软件包的ID列表
     */

    void printUninstallList(const vector<std::string> &uninstallId);

    /**
     * @brief 展示用户选择是否假设为卸载操作的提示信息
     * 
     * @param pmOptions 卸载时的选项参数
     * @return bool 用户是否选择了假设卸载操作
     */
    bool printAssumeUninstallYesChoice(PackageManagerOptions pmOptions);

    /**
     * @brief 卸载指定的应用
     * 
     * @param name 要卸载的应用名称
     * @return bool 卸载是否成功
     */
    bool uninstallApp(const std::string &name);

    /**
     * @brief 卸载指定的运行时
     * 
     * @param name 要卸载的运行时名称
     * @return bool 卸载是否成功
     */
    bool uninstallRuntime(const std::string &name);

    /**
     * @brief 卸载指定的base
     * 
     * @param name 要卸载的base名称
     * @return bool 卸载是否成功
     */
    bool uninstallBase(const std::string &name);

    /**
     * @brief 从存储库中删除指定应用或运行时的引用
     * 
     * @param name 要删除引用的应用或运行时名称
     * @return bool 删除是否成功
     */
    bool deleteRefsFromRepo(const std::string &name);

    /**
     * @brief 删除指定应用或运行时的用户数据
     * 
     * @param name 要删除用户数据的应用或运行时名称
     * @return bool 删除是否成功
     */
    bool deleteUserData(const std::string &name);

    /**
     * @brief 更新软件包
     * 
     * @param vectorIds 解析的 ref 列表
     * @param pmOptions 用户输入的参数
     * @return int 执行返回
     */
    int update(const vector<string>& vectorIds, PackageManagerOptions pmOptions);

    /**
     * @brief 搜索远程所有软件包
     * *@param vectorIds 解析的 ref 列表
     * @param pmOptions 用户输入的参数
     * @return int 
     */
    int search(const string &vectorId, PackageManagerOptions pmOptions);  

    /**
     * @brief 更新软件包
     * 
     * @param vectorIds 解析的 ref 列表
     * @param pmOptions 用户输入的参数
     * @return string  完整路径
     */
    string searchInfo(const string& vectorIds, PackageManagerOptions pmOptions);

    /**
     * @brief 对于已安装软件包中存在损坏的文件进行修复
     * 
     * @return int 
     */
    int repair();

    /**
     * @brief 当前 ref 是否安装
     * 
     * @param pmRef 
     * @return true 
     * @return false 
     */
    bool currentRefIsInstalled(KMPMRef &pmRef);


    /**
     * @brief 当前包是否安装, 给软件商店使用
     *
     * @param name
     * @return int
     */
    int isInstalled(string name);

    /**
     * @brief 得到 summary.json 并解析
     * 
     * @param summaryUrl summary.json 路径
     * @param isExpired summary.json 是否过期
     * @return  是否下载 summary.json 并解析成功, KM_ERROR_NO 表示成功
     */
    int getRemoteSummary(const string &summaryUrl, bool isExpired);

    /**
     * @brief 遍历取得所有符合条件的依赖列表
     * 
     * @param vectorIds 用户输入的 ref 列表
     * @param pmOptions 用户输入的参数
     * @param taskType 任务类型
     * @return int 返回操作结果
     */
    int getAllFuzzyMatchRefVector(const vector<string> &vectorIds, PackageManagerOptions pmOptions, TaskType taskType);

    /**
     * @brief 获取真正安装列表
     * 
     * 对获取的所有依赖列表重新封装 KMPMRef ，再次进行是否安装过滤操作。原因是 app 依赖 base, runtime，但 base, runtime 会重新出现在依赖列表中
     * 
     * @param taskType 任务类型
     */
    void getDownloadRefList(TaskType taskType);

    /**
     * @brief  打印安装列表
     * 
     */
    void printDownloadRefList(const vector<KMPMRef> &downloadRefs);

    /**
     * @brief 用户选择是否展示信息
     * 
     * @param pmOptions 
     */
    bool printAssumeYesChoice(PackageManagerOptions pmOptions);

    /**
     * @brief 进度处理回调函数
     *
     * 进度条处理分成3个步骤：
     *  - 1. 当拉取 metadata 时， 增长到 5%;
     *  - 2. 下载数据一直到 97%;
     *  - 3. 写入 ostree objects 为最后的 3%
     *
     * @param progressStatus 在 ostree pull 时，发送的进度等信息结构体
     */
    static void progressCallback(ProgressStatus progressStatus);

    /**
     * @brief 增加最后写入对象的 3% 进度
     * 
     * @param outstandingWrites 
     * @return int 
     */
    static int getWriteProgress(int outstandingWrites);

    /**
     * @brief 返回要下载列表所有的安装大小总和
     * 
     * @return uint64_t 下载列表所有的安装大小总和
     */
    static uint64_t getTotalSize();

    /**
     * @brief 得到当前进度条下载的completedRef 对应的要安装大小
     * 
     * @param completedRef 当前进度条下载的completedRef 
     * @param id 当前进度条下载的id
     * @return uint64_t 安装大小
     */
    static uint64_t getSingleSize(string completedRef, string &id);

    /**
     * @brief 更新进度信息
     * 
     */
    static void updateProgress();

    /**
     * @brief 格式化时间
     * 
     * @param duration ostree 返回的时间
     * @return string 格式后的时间
     */
    static string formatDuration(guint64 duration);

    /**
     * @brief 计算需要下载时间
     * 
     * @param speed 下载速度
     * @param sizeBytes 下载的字节数
     * @return std::string 需要下载的时间
     */
    static std::string calculateDownloadTime(const std::string &speed, guint64 sizeBytes);

    /**
     * @brief 部署数据
     * 
     * @param ostreeManager ostree 操作句柄
     * @return int 部署状态
     */
    int deploy(KMOSTreeHandler &ostreeManager);


    /**
     *  @brief 检查文件是否存在，如果不存在则创建文件并输入空字符串
     *
     *  新建 "active/files/.ref"，并输入空字符串 ""
     * 
     * @param filename 
     */
    void createFileForEmptyString(const std::string &filename);


    /**
     * @brief 更改service文件
     *
     * @param pmRef
     * @param serviceFileDirectoryPath
     */
    void modifyServiceFile(KMPMRef &pmRef, string serviceFileDirectoryPath);

    /**
     * @brief 获取当前目录下的所有文件
     *
     * 对于获取service文件有用
     *
     * @param directoryPath
     * @param files
     * @return true
     * @return false
     */
    bool getAllFilesInDirectory(const std::string &directoryPath, std::vector<std::string> &files);


    /**
     * @brief 读取 .desktop 文件内容
     *
     * @param filename
     * @return std::vector<std::string>
     */
    std::vector<std::string> getDataFromKVFile(const std::string &filename);


    /**
     * @brief 修改 .desktop 文件内容
     *
     * @param filename
     * @param newLines
     * @return true
     * @return false
     */
    bool setDataToKVFile(const std::string &filename, const std::vector<std::string> &newLines);

    /**
     * @brief 更改desktop文件，比如修改Exec, Icon, X-Kaiming
     *
     * @param pmRef
     * @param exportDesktopFilePath
     */
    void modifyDesktopFile(KMPMRef &pmRef, string exportDesktopFilePath);


    /**
     * @brief 创建一个 entries/bin/ref.id shell脚本，写入执行内容，并赋予0755权限
     *
     * @param fileName
     * @param pmRef
     * @return true
     * @return false
     */
    bool createExportBinShellScript(KMPMRef pmRef, string fileName);

    /**
     * @brief 当文件不存在时创建一个文件，并记录当前时间
     * 
     * @param fileName 
     * @return true 
     * @return false 
     */
    bool createFileIfNotExist(string fileName);

    /**
     * @brief 递归遍历exports/目录并处理文件，比如创建软链接
     *
     * @param ref
     * @param srcDir
     * @param destDir
     */
    void modifyExportsDirectory(KMPMRef &ref, const std::string &srcDir, const std::string &destDir);

    /**
     * @brief 接受不定数量的 cacheShellPath 参数，并将它们拼接到命令中，然后执行命令
     *
     * 作用是生成应用desktop, icon, service等缓存
     *
     * @param cacheShellPaths
     */
    void runMultiperTriggerUpdateCacheCommand(const vector<string> &cacheShellPaths);


    /**
     * @brief 接受不定数量的 cacheShellPath 参数，并将它们拼接到命令中，然后执行命令
     *
     *
     * @param cacheShellPaths
     */
    void runTriggerUpdateCacheCommand(const std::string &cacheShellPath);

    static std::once_flag initFlag;
    static std::vector<std::string> drivers;

    /**
     * @brief 获取GL驱动列表
     * 
     * @return vector<string>  GL驱动列表
     */
    vector<string> getGLDrivers();

private:
    /**
     * @brief 从环境变量KAIMING_GL_DRIVERS中获取GL驱动列表
     * 
     * @return vector<string> 环境变量KAIMING_GL_DRIVERS中获取GL驱动列表
     */
    vector<string> parseGLDriversFromEnv();

    /**
     * @brief 从系统文件/sys/module/nvidia/version中获取GL驱动列表
     * 
     * @return vector<string> 系统文件/sys/module/nvidia/version中获取GL驱动列表
     */
    vector<string> parseGLDriversFromSystem();

private:
    class Private;
    std::shared_ptr<Private> d;
    std::unordered_map<std::string, KMInfoJson> infoMap;
};

#endif