/* common/KMBuildinsUtils.h
 *
 * Copyright (C) 2023 OpenKylin, Inc
 */

#ifndef __KMBUILDINSUTILS_H__
#define __KMBUILDINSUTILS_H__

#include <string>
#include <tuple>

#include "KMCommonTypePrivate.h"
#include "KMConfig.h"
#include "KMFileInfo.h"
#include "KMOstreeMutableTree.h"
#include "KMOstreeRepoCommitModifier.h"
#include "KMStorageDir.h"

#define KAIMING_SPARSE_CACHE_KEY_ENDOFLINE "eol"
#define KAIMING_SPARSE_CACHE_KEY_ENDOFLINE_REBASE "eolr"
#define KAIMING_SPARSE_CACHE_KEY_TOKEN_TYPE "tokt"
#define KAIMING_SPARSE_CACHE_KEY_EXTRA_DATA_SIZE "eds"

#define KAIMING_SUMMARY_HISTORY_LENGTH_DEFAULT 16

/**
 * @brief : 主要用于封装一些子命令通用的业务相关的操作，但又不像KMUtil那么通用
 */
class KMBuildinsUtils
{
    KMBuildinsUtils() = delete;
    ~KMBuildinsUtils() = delete;

public:
    /**
     * findInstalledPref:
     * @brief : 根据入参条件判断app或runtime、sdk是否安装
     * @param : [in] pref，形如"org.videolan.VLC"或"runtime/org.freedesktop.Sdk/x86_64/22.08"
     * @param : [in] kinds，开明包安装目录类型，app还是runtime等
     * @param : [in] defaultArch，默认查询架构，如果pref里面没有架构信息则默认采用defaultArch
     * @param : [in] defaultBranch，默认查询版本，如果pref里面没有版本信息则默认采用defaultBranch
     * @param : [out] outRef，如果查到已经安装，则返回KMRef里的信息
     * @param : [out] errMsg，保存错误信息
     * @return: 如果在系统级安装目录（当前仅支持系统级安装目录）中查找到安装信息则返回系统安装目录构造的KMStorageDir对象；否则，返回一个空的KMStorageDir对象
     */
    static KMStorageDir findInstalledPref(const std::string &pref, KaimingKinds kinds, const std::string &defaultArch, const std::string &defaultBranch, KMRef &outRef, std::string &errMsg);

    /**
     * splitPartialRefArg:
     * @brief : 解析参数pref中的信息，获取里面的id、arch、branch等信息
     * @param : [in] pref，形如"org.videolan.VLC"或"runtime/org.freedesktop.Sdk/x86_64/22.08"
     * @param : [in] defaultArch，默认查询架构，如果pref里面没有架构信息则默认采用defaultArch
     * @param : [in] defaultBranch，默认查询版本，如果pref里面没有版本信息则默认采用defaultBranch
     * @param : [out] kinds，开明包安装目录类型，app还是runtime等
     * @param : [out] errMsg，保存错误信息
     * @return: 返回id、arch、branch等信息
     */
    static KMRef splitPartialRefArg(const std::string &pref, const std::string &defaultArch, const std::string &defaultBranch, KaimingKinds &kinds, std::string &errMsg);

    /**
     * prefToKMRef:
     * @brief : 将pref转换为KMRef对象
     * @param : [in] kind，开明包安装目录类型，app还是runtime等
     * @param : [in] pref，形如"org.freedesktop.Sdk/x86_64/22.08"或"runtime/org.freedesktop.Sdk/x86_64/22.08"
     * @return: 解析pref转换成的KMRef对象
     */
    static KMRef prefToKMRef(const KaimingKinds &kind, const std::string &pref);

    /**
     * isValidAppName:
     * @string: The string to check
     *
     * Checks if @string is a valid application name.
     *
     * App names are composed of 3 or more elements separated by a period
     * ('.') character. All elements must contain at least one character.
     *
     * Each element must only contain the ASCII characters
     * "[A-Z][a-z][0-9]_-". Elements may not begin with a digit.
     * Additionally "-" is only allowed in the last element.
     *
     * App names must not begin with a '.' (period) character.
     *
     * App names must not exceed 255 characters in length.
     *
     * The above means that any app name is also a valid DBus well known
     * bus name, but not all DBus names are valid app names. The difference are:
     * 1) DBus name elements may contain '-' in the non-last element.
     * 2) DBus names require only two elements
     *
     * Returns: %TRUE if valid, %FALSE otherwise.
     */
    static bool isValidAppName(const std::string &appName, std::string &errMsg);

    /**
     * isValidBranch:
     * @string: The string to check
     * @string: return location for an error
     *
     * Checks if @string is a valid branch name.
     *
     * Branch names must only contain the ASCII characters
     * "[A-Z][a-z][0-9]_-.".
     * Branch names may not begin with a period.
     * Branch names must contain at least one character.
     *
     * Returns: %TRUE if valid, %FALSE otherwise.
     */
    static bool isValidBranch(const std::string &branch, std::string &errMsg);

    /**
     * @brief : 根据metadata信息获取extension列表
     * @param : [in] metadata, metadata信息
     * @param : [in] defaultArch，默认架构
     * @param : [in] defaultBranch，默认分支
     * @return: extension列表
     */
    static std::vector<KMExtension> listExtensions(const std::shared_ptr<KMMetaData> &metadata, const std::string &defaultArch, const std::string &defaultBranch);

    /**
     * parseExtensionWithTag：
     * @brief : 解析带tag的extension
     * @param : [in] extension, metadata文件中配置的extension等
     * @param : [out] name, 解析后得到的externsion的id
     * @param : [out] tag, 解析后得到的tag
     */
    static void parseExtensionWithTag(const std::string &extension, std::string &name, std::string &tag);

    /**
     * isValidInitialNameCharacter:
     * @brief : 是否合法的命名字符
     * @param : [in] c, 待判断字符
     * @param : [in] allowDash，是否运行横线连接符'-'
     */
    static bool isValidInitialNameCharacter(int c, bool allowDash);
    static bool isValidNameCharacter(int c, bool allowDash);

    /**
     * checkRequiredVersion:
     * @brief : 校验kaiming包版本要求
     * @param : [in] required_versions，要求的版本号列表
     * @param : [out] errMsg，错误信息
     * @return: true-满足开明包版本要求；false-不满足版本要求
     */
    static bool checkRequiredVersion(const std::vector<std::string> &requiredVersions, std::string &errMsg);

    /**
     * repoResolveRev:
     * @brief : 根据给定参数查找校验和，并在outRev中返回
     * @param : [in] repo, ostree仓库
     * @param : [in] collectionId，ostree仓库的collectionId
     * @param : [in] remoteName
     * @param : [in] refName
     * @param : [in] allowNoent
     * @param : [out] outRev，校验和
     * @param : [out] errMsg，错误信息
     */
    static bool repoResolveRev(KMOstreeRepo *repo, const std::string &collectionId, const std::string &remoteName, const std::string &refName, bool allowNoent, std::string &outRev,
                               std::string &errMsg);

    /**
     * mtreeEnsureDirMetadata:
     * @brief : 创建ostree仓库根目录元数据
     */
    static bool mtreeEnsureDirMetadata(KMOstreeRepo *repo, KMOstreeMutableTree *tree, std::string &errMsg);

    /**
     * pathMatchPrefix:
     * @brief : 判断路径string是否匹配pattern前缀，返回匹配结束后的部分字符串
     * @param : [in] pattern, 前缀模式
     * @param : [in] string, 路径
     * @return: 返回匹配结束后的部分字符串，不匹配返回null；Returns end of matching path kaiming, or null if no match
     */
    static const char *pathMatchPrefix(const char *pattern, const char *string);

    /**
     * repoCollectSizes:
     * @brief : 获取仓库安装、下载大小
     * @param : [in] repo, ostree仓库
     * @param : [in] file, 里面封装了OstreeRepoFile对象指针
     * @param : [in] fileInfo，里面封装了GFileInfo对象指针
     * @param : [out] installedSize， 返回安装大小
     * @param : [out] downloadSize，返回下载大小
     * @param : [ount] errMsg，错误信息
     * @return: 返回操作是否成功
     */
    static bool repoCollectSizes(KMOstreeRepo &repo, KMFile &file, KMFileInfo *fileInfo, std::uint64_t &installedSize, std::uint64_t &downloadSize, std::string &errMsg);

    /**
     * @brief 	 收集附加数据大小
     * @param 	 repo [in], ostree仓库
     * @param 	 rev [in], 校验和
     * @param 	 installedSize [out], 返回安装大小
     * @param 	 downloadSize [out], 返回下载大小
     */
    static void repoCollectExtraDataSizes(KMOstreeRepo &repo, const std::string &rev, std::uint64_t &installedSize, std::uint64_t &downloadSize);

    /**
     * @brief : 收集附加数据大小
     * @param : [in] repo, ostree仓库
     * @param : [in] rev, 校验和
     * @param : [out] extraDataSources, 额外数据源
     * @param : [out] errMsg, 错误信息
     * @return: true 成功； false 失败
     */
    static bool repoGetExtraDataSources(KMOstreeRepo &repo, const std::string &rev, KMVariant &extraDataSources, std::string &errMsg);

    /**
     * @brief : 从commitv中获取对应的附加数据源
     * @param : [in/out] commitv, ostree提交数据
     * @param : [in/out] extraDataSources, 附加数据源
     * @param : [in/out] errMsg, 错误信息
     * @return: true 成功； false 失败
     */
    static bool commitGetExtraDataSources(KMVariant &commitv, KMVariant &extraDataSources, std::string &errMsg);

    /**
     * @brief : 解析附加数据源
     * @param : [in] extraDataSources, 附加数据源
     * @param : [in] index, 索引
     * @param : [out] name, 名称
     * @param : [out] downloadSize, 返回下载大小
     * @param : [out] installedSize, 返回安装大小
     * @param : [out] sha256, 返回sha256的checksum
     * @param : [out] uri
     */
    static void repoParseExtraDataSources(KMVariant &extraDataSources, int index, const char **name, std::uint64_t &downloadSize, std::uint64_t &installedSize, const guchar **sha256,
                                          const char **uri);

    /**
     * @brief : 获取ostree仓库中summary历史长度
     * @param : [in] repo, ostree仓库
     * @return: std::uint32_t 历史记录数量
     */
    static std::uint32_t repoGetSummaryHistoryLength(KMOstreeRepo &repo);

    /**
     * @brief : 根据ref字符串获取arch
     * @param : [in] ref, 形如：app/${id}/${arch}/${branch}
     * @return: 是否是app、runtime、appstream的ref
     */
    static bool isAppOrRuntimeOrAppstreamRef(const std::string &ref);

    /**
     * @brief : 根据ref字符串获取arch
     * @param : [in] ref, 形如：app/${id}/${arch}/${branch}
     * @return: arch
     */
    static std::string getArchForRef(const std::string &ref);

    /**
     * @brief : 解压缩
     * @param : [in] bytes, 待解压数据
     * @param : [out] error, 错误信息
     * @return: GBytes* ，解压后的数据
     */
    static GBytes *zlibDecompressBytes(GBytes *bytes, GError **error);
    /**
     * @brief : 解压缩
     * @param : [in] bytes, 待解压数据
     * @param : [in] level，压缩级别
     * @param : [out] error, 错误信息
     * @return: GBytes* ，解压后的数据
     */
    static GBytes *zlibCompressBytes(GBytes *bytes, int level, GError **error);

    /**
     * @brief : 从ostree仓库中加载DigestedSummary
     * @param : [in] repo, ostree仓库
     * @param : [in] digest
     * @param : [out] errMsg, 错误信息
     * @return: KMVariant ，DigestedSummary
     */
    static KMVariant repoLoadDigestedSummary(KMOstreeRepo &repo, const std::string &digest, std::string &errMsg);

    /**
     * @brief : 从ostree仓库中加载SummaryIndex
     * @param : [in] repo, ostree仓库
     * @param : [out] errMsg, 错误信息
     * @return: KMVariant ，SummaryIndex
     */
    static KMVariant repoLoadSummaryIndex(KMOstreeRepo &repo, std::string &errMsg);

    /**
     * @brief : 更新ostree仓库中的summary信息
     * @param : [in/out] repo, ostree仓库
     * @param : [in/out] flags, 更新标志
     * @param : [in/out] gpgKeyIds
     * @param : [in/out] gpgHomeDir
     * @param : [in/out] errMsg
     * @return: true-成功；false-失败
     */
    static bool repoUpdate(KMOstreeRepo &repo, KMRepoUpdateFlags flags, const std::vector<std::string> &gpgKeyIds, const std::string &gpgHomeDir, std::string &errMsg);
};

#endif // !__KMBUILDINSUTILS_H__
