#pragma once

#include <saas/library/sandbox/sandbox_meta/sandbox_manager.h>

#include <robot/library/skynet/skynet_common.h>

#include <util/generic/string.h>
#include <util/generic/hash.h>
#include <util/generic/hash_set.h>
#include <util/generic/maybe.h>

#include <functional>

class TFsPath;

namespace NOxygen {

    class TRecipeConfigProto;
    class TRecipeFileConfigProto;
    class TSandboxFileInfoProto;
    class TStaticDataOptions;
}

namespace NSaas {

    struct TSandboxOptions {
        bool UseSandbox = true;
        bool UseSkyNet = true;
        bool UseCustomJsonConfigPath = false;
        TString CustomJsonConfigPath;
    };

    class TSandboxDownloader {
       private:
           using TResType2Info = THashMap<TString, NSaas::TSandboxResourceInfo>;

           const TFsPath Dir;
           TSandboxOptions Options;

           const TResType2Info ResType2Info;
           THashSet<TString> DownloadedResourceTypes;
           THashSet<TString> ForceRsyncResourceTypes;

           const TFsPath DownloadDir;
           const bool KeepDownloadDir;
       public:
           TSandboxDownloader(const TFsPath& dir, const TSandboxOptions& options, bool keepDownloadDir);
           ~TSandboxDownloader();

           void SetCustomJsonConfigPath(const TString& path);

           bool Download(const NOxygen::TSandboxFileInfoProto& sandboxInfo, const TFsPath& destination,
               bool throwOnError, bool quiet, bool keepSkyNetDownloadDir, std::function<void(const TString& path)> f);
           TMaybe<NOxygen::TSkyFileInfo> GetFileInfo(const NOxygen::TSandboxFileInfoProto& sandboxInfo);


       private:
           bool DownloadResourceViaSkyNetIfNeeded(const NSaas::TSandboxResourceInfo& resInfo);

           void MoveSkyNetDownloadedFileToCatalog(const NOxygen::TSandboxFileInfoProto& sandboxInfo, const TFsPath& destination, bool keepSource = false);

           static TResType2Info CreateResType2Info(const TFsPath& dir, const TSandboxOptions& options);
    };

    void DownloadRecipeFiles(
        const NOxygen::TRecipeConfigProto& recipe,
        const TFsPath& destDir,
        bool throwOnError,
        bool toShard,
        bool quiet,
        bool keepSkyNetDownloadDir,
        bool useSandbox = false
    );
    void DownloadRecipeFilesImpl(
        const NOxygen::TRecipeConfigProto& recipe,
        const TFsPath& destDir,
        bool throwOnError,
        bool toShard,
        bool quiet,
        bool keepSkyNetDownloadDir,
        const TSandboxOptions& options,
        std::function<void(const TString& path)> beforeCallback,
        const TMaybe<std::function<void(const TString& path)>>& afterCallback = Nothing(),
        std::function<bool(const TString& destination)> filterCallback = {}
    );
    void DownloadFiles(
        const TString& rbTorrent,
        const TFsPath& destDir,
        const TFsPath& tmpDir
    );

    NOxygen::TRecipeConfigProto BuildRecipeFromStaticDataOptions(const NOxygen::TStaticDataOptions&);

} // namespace NOxygen
