#include "common.h"
#include "rty_diff.h"
#include "searchmap.h"
#include "environment.h"
#include "proxy.h"
#include "sla_description.h"
#include <saas/deploy_manager/scripts/common/deploy/deploy_builder.h>
#include <saas/deploy_manager/scripts/common/global_names/global_names.h>
#include <library/cpp/json/json_reader.h>
#include <library/cpp/string_utils/quote/quote.h>

namespace NRTYDeploy {
    const TString TFileContentGenerator::ServiceNameMacros = "%SERVICENAME%";

    TFileContentGenerator::TPtr TFileContentGenerator::Deserialize(const NJson::TJsonValue& json) {
        TPtr result = TFactory::Construct(json["type"].GetStringRobust());
        if (!!result) {
            result->DoDeserialize(json);
        } else {
            ythrow yexception() << "Can't find correct FileContentGenerator. Check filename argument";
        }
        return result;
    }

    TFileContentGenerator::TPtr TFileContentGenerator::Deserialize(const ICommonData& common, TContext& context, const TString& root, const TString& filename, i64 version) {
        NJson::TJsonValue json;
        TStringInput si(filename);
        if (!NJson::ReadJsonTree(&si, &json)) {
            TFsPath path = TFsPath(root + "/" + context.SlotInfo.Service + "/" + filename);
            if (context.SlotInfo.ConfigType != "default")
                path = path.GetPath() + "$" + context.SlotInfo.ConfigType + "$";

            NSaas::TSlotInfo slotInfo;
            slotInfo.CType = context.SlotInfo.CType;
            slotInfo.ServiceType = INDEXER_PROXY_SERVICE;
            if (NRTYDeployInfo::IDeployComponentInfo::TFactory::Has(context.SlotInfo.Service))
                slotInfo.ServiceType = context.SlotInfo.Service;
            return Create(path, common, slotInfo, version);
        }
        context.DeserializeFromJson(json["context"]);
        return Deserialize(json["generator"]);
    }

    void TFileContentGenerator::Serialize(NJson::TJsonValue& json) const {
        json.InsertValue("type", GetType());
    }

    bool TFileContentGenerator::SerializeWithContext(TString& result, const TContext& context) const {
        NJson::TJsonValue json;
        context.SerializeToJson(json.InsertValue("context", NJson::JSON_MAP));
        Serialize(json.InsertValue("generator", NJson::JSON_MAP));
        result = json.GetStringRobust();
        CGIEscape(result);
        return true;
    }

    void TFileContentGenerator::DoDeserialize(const NJson::TJsonValue& /*json*/) {
    }

    void TFileContentGenerator::SetLastVersion() {
    }

    bool TFileContentGenerator::GetContentHash(TString& result, const ICommonData& common, const TContext& context) const {
        TString content;
        if (!GetContent(content, common, context))
            return false;
        result = MD5::Calc(content);
        return true;
    }

    TFileContentGenerator::TPtr TFileContentGenerator::Create(const TFsPath& path, const ICommonData& common, const NSaas::TSlotInfo& slotInfo, i64 version /*= -1*/) {
        if (path.GetName().StartsWith("rtyserver.diff"))
            return new TRtyDiffFileContentGenerator(path, "rtyserver.conf-default", "rtyserver.conf-common", "Server.", common, slotInfo.CType, slotInfo.Service, version);
        if (path.GetName().StartsWith("cluster.meta"))
            return new TSearchMapContentGenerator(common, slotInfo.CType, slotInfo.ServiceType, version);
        if (path.GetName().StartsWith("environment"))
            return new TEnvironmentFileContentGenerator(path, common, version);
        if (path.GetName().StartsWith("indexerproxy-") || path.GetName().StartsWith("searchproxy-") || path.GetName().StartsWith("query-language-")) {
            return new TProxyFileContentGenerator(path, common, slotInfo.Service, version);
        }
        if (path.GetName().StartsWith("sla_description-")) {
            return new TSlaDescriptionFileContentGenerator(path, common, slotInfo.Service, version);
        }
        return new TPlainFileContentGenerator(path, common, version);
    }

    ui32 TFileContentGenerator::AddGenerators(TVector<TPtr>& list, const ICommonData& common, const TFsPath& path, const TString& filenamePrefix, const NSaas::TSlotInfo& slotInfo) {
        TVector<TString> nodes;
        ui32 count = 0;
        common.GetStorage().GetNodes(path.GetPath(), nodes);
        for (TVector<TString>::const_iterator i = nodes.begin(); i != nodes.end(); ++i) {
            if (i->StartsWith(filenamePrefix)) {
                list.push_back(Create(path / *i, common, slotInfo));
                ++count;
            }
        }
        return count;
    }

    TFileContentGenerator::TContext::TContext()
        : NoAnyPatch(false)
    {}

    bool TFileContentGenerator::TContext::DeserializeFromJson(const NJson::TJsonValue& json) {
        NoAnyPatch = json["no_patch"].GetBooleanRobust();
        if (!SlotInfo.DeserializeFromJson(json["slot_info"])) {
            return false;
        }
        return true;
    }

    void TFileContentGenerator::TContext::SerializeToJson(NJson::TJsonValue& json) const {
        json.InsertValue("no_patch", NoAnyPatch);
        json.InsertValue("slot_info", SlotInfo.SerializeToJson());
    }

}
