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

#ifndef __BUILD_CONTEXT_H__
#define __BUILD_CONTEXT_H__

#include <filesystem>
#include <iostream>
#include <string>
#include <vector>

#include <boost/program_options.hpp>
#include <gio/gio.h>

#include "KMBuilderConfig.h"
#include "KMBuilderConfigJson.h"
#include "KMBuilderConfigYaml.h"
#include "KMBuilderManifest.h"
#include "KMBuilderSdkConfig.h"
#include "common/KMSingleton.h"

namespace opt = boost::program_options;
namespace fs = std::filesystem;

#define STATE_DIR ".kaiming-builder"
#define builderContext KMBuilderContext::instance()

class KMBuilderContext : public KMSingleton<KMBuilderContext>
{
public:
    KMBuilderContext(token);
    ~KMBuilderContext();

    void parseCommandLine(int argc, char **argv);
    void loadConfig();

    std::string getArch() const;

    bool isBuildOnly() const { return m_isBuildOnly; }

    bool isExportOnly() const { return m_isExportOnly; }

    bool isFinishOnly() const { return m_isFinishOnly; }

    bool isForceClean() const { return m_isForceClean; }

    bool isPackage() const { return m_isPackage; }

    bool isPackageOnly() const { return m_isPackageOnly; }

    bool isCcache() const { return m_isCcache; }

    std::string getRepo() const { return m_repo; }

    std::string getBaseDir() const { return m_baseDir.string(); }

    std::string getAppDir() const { return m_appDir.string(); }

    std::string getRunDir() const { return m_runDir.string(); }

    std::string getStateDir() const { return m_stateDir.string(); }

    std::string getCcacheDir() const { return m_ccacheDir.string(); }

    std::string getCacheDir() const { return m_cacheDir.string(); }

    std::string getBuildDir() const { return m_buildDir.string(); }

    std::string getDownloadsDir() const { return m_downloadsDir.string(); }

    bool getIsKeepBuildDirs() { return m_isKeepBuildDirs; }

    int getJobs() const { return m_jobs; }

    std::string getStopat() const { return m_stopAt; }

    std::string getConfigFile() const { return m_configFile; }

    std::shared_ptr<KMBuilderManifest> manifestConfig() { return m_manifestConfig; }

    // 下面的get方法会被废弃
    bool isSandbox() const { return m_isSandbox; }
    const string getSubject() { return m_subject; }
    const string getBody() { return m_body; }
    const string getGpgHomeDir() { return m_gpgHomeDir; }
    const int getTokenType() { return m_tokenType; }
    bool getIsDisableRofilesFuse() { return m_isDisableRofilesFuse; }
    bool getIsRequireChanges() { return m_isRequireChanges; }
    std::shared_ptr<KMBuilderConfig> getBuilderConfig() { return m_builderConfig; }
    string getDefaultBranch() { return m_defaultBranch; }
    string getMirrorScreenshotsUrl() { return m_mirrorScreenshotsUrl; }
    int64_t getOverrideSourceDateEpoch() { return m_overrideSourceDateEpoch; }
    KMBuilderSdkConfig *getBuilderSdkConfig() { return m_sdkConfig; }
    bool getIsSandbox() { return m_isSandbox; }
    bool getIsDeleteBuildDirs() { return m_isDeleteBuildDirs; }
    bool getIsBundleSources() { return m_isBundleSources; }

private:
    void showUsage() const
    {
        if (m_optionsShowDescription != nullptr)
            cout << *m_optionsShowDescription << endl;
    }

    void showCmdline() const;
    void addOptions();
    void addBuilderOptions(opt::options_description &builderOptions);
    void checkOptions();

private:
    int m_argc;
    char **m_argv;

    std::string m_programName;
    opt::options_description *m_optionsDescription = nullptr;
    opt::positional_options_description *m_optionsPositionalDescription = nullptr;
    opt::options_description *m_optionsShowDescription = nullptr;

    // 命令行选项域
    bool m_isHelp = false;
    bool m_isVerbose = false;
    std::string m_arch;
    bool m_isCcache = false;
    bool m_isBuildOnly = false;
    bool m_isFinishOnly = false;
    bool m_isExportOnly = false;
    bool m_isForceClean = false;
    bool m_isSandbox = false;
    std::string m_stopAt;
    int m_jobs = -1;
    bool m_isKeepBuildDirs = false;
    
    std::string m_manifest;

    // 下面命令行选项会废弃
    std::string m_defaultBranch;
    bool m_isDisableRofilesFuse = false;
    bool m_isBundleSources = false;
    bool m_isRequireChanges = false;
    bool m_isDeleteBuildDirs = false;
    std::string m_subject;
    std::string m_body;
    int m_tokenType = -1;
    std::string m_gpgHomeDir;
    std::string m_mirrorScreenshotsUrl;
    int64_t m_overrideSourceDateEpoch = -1;
    bool m_isPackage = false;
    bool m_isPackageOnly = false;
    std::string m_repo;

private:
    // 数据成员域

    // 构建清单配置
    std::shared_ptr<KMBuilderManifest> m_manifestConfig;

    // 构建过程中涉及的目录
    fs::path m_baseDir;
    fs::path m_appDir;
    fs::path m_runDir;
    fs::path m_stateDir;
    fs::path m_cacheDir;
    fs::path m_downloadsDir;
    fs::path m_checksumDir;
    fs::path m_ccacheDir;
    fs::path m_buildDir;
    std::string m_configFile;

    // 下面成员后面会废弃
    KMBuilderSdkConfig *m_sdkConfig;
    std::shared_ptr<KMBuilderConfig> m_builderConfig;
};

#endif // !__BUILD_CONTEXT_H__
