/*
 * Copyright 2018 Bloomberg Finance LP
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef INCLUDED_BUILDBOXCASD_DAEMON
#define INCLUDED_BUILDBOXCASD_DAEMON

#include <cstddef>
#include <optional>
#include <string>

#include <buildboxcommon_commandline.h>
#include <buildboxcommon_connectionoptions.h>
#include <buildboxcommon_logging.h>
#include <buildboxcommon_protos.h>

#include <buildboxcasd_server.h>

namespace buildboxcasd {

namespace proto {
using namespace build::bazel::remote::execution::v2;
} // namespace proto

class Daemon {
  public:
    Daemon() = default;
    bool configure(const buildboxcommon::CommandLine &cml,
                   const std::string &cachePath);
    /**
     * Connect to the Bots and CAS servers and run jobs until
     * `stop()` is called.
     */
    void runDaemon();

    void stop();

    std::shared_ptr<Server> d_server;
    bool d_shutdown = false;

    buildboxcommon::ConnectionOptions d_cas_server;
    buildboxcommon::ConnectionOptions d_ra_server;
    buildboxcommon::ConnectionOptions d_ac_server;
    buildboxcommon::ConnectionOptions d_exec_server;

    std::vector<std::string> d_proxyInstanceNames;
    // Map proxy instance to remote instance
    std::unordered_map<std::string, std::string> d_instanceMappings;
    std::vector<std::string> d_localServerInstanceNames;
    std::string d_local_cache_path;
    std::vector<std::string> d_bind_addresses;
    std::vector<std::string> d_socket_paths;
    std::optional<gid_t> d_socket_gid;
    std::optional<mode_t> d_socket_mode;
    std::optional<int> d_permitKeepaliveTime;
    std::optional<int> d_shutdownDeadline;

    // Local execution service
    std::string d_runnerCommand;
    std::vector<std::string> d_extraRunArgs;
    int d_maxJobs = 0;
    std::optional<int> d_execHybridQueueLimit;
    bool d_enableFallbackToLocalExecution = false;
    bool d_cacheFailures = false;

    std::optional<int64_t> d_quotaHigh = 0;
    double d_quotaLowRatio = 0;
    int64_t d_reserved_space = 0;
    bool d_protect_session_blobs = false;
    bool d_failFastDuringCleanup = false;
    bool d_allow_external_file_moves = false;
    bool d_read_only_remote = false;
    buildboxcommon::LogLevel d_log_level = buildboxcommon::ERROR;
    bool d_storeWritableObjects = false;

    unsigned int d_proxy_findmissingblobs_cache_ttl_seconds = 0;
    unsigned int d_proxyAcValidationCacheTtlSeconds = 0;

    size_t d_numDigestThreads = 0;
    size_t d_numIOThreads = 0;
    std::shared_ptr<std::unordered_set<std::string>>
        d_allowedPreUnstageCommands = nullptr;

    static buildboxcommon::LogLevel defaultLogLevel()
    {
        return buildboxcommon::LogLevel::ERROR;
    }

  private:
    void logCommandLine() const;
};

} // namespace buildboxcasd

#endif
