#pragma once

#include "action.h"
#include "lables.h"

#include <saas/library/behaviour/behaviour.h>

namespace NSaas {
    class TJsonDeserializer {
    public:
        void Deserialize(const NJson::TJsonValue& source, TAction& target);
    private:
        struct TActionParsingContext {
            const TRTYMessageBehaviour* Action = nullptr;
            TString Request;
            bool HasDocumentSection = false;
            bool HasPrefix = false;
        };

        struct TDocParsingContext {
            bool HasBody = false;
            bool HasURL = false;
            bool HasZone = false;
            bool HasIndDoc = false;
        };

        struct TZoneParsingContext {
            bool HasOptions = false;
            bool HasType = false;
            bool HasValue = false;
            bool HasChildren = false;
        };
    private:
        TActionParsingContext ParsingContext;
        TDocParsingContext DocParsingContext;

    private:
        enum class EFactorsType {Int, Float};
        void ProcessZoneZone(const TString& name, const NJson::TJsonValue& zone, NSaas::TZone& parent);
        void ProcessZoneDirectives(const TString& name, const NJson::TJsonValue& zone, TZoneParsingContext &zpc, TSet<NJsonFormat::TEntity::EType>& types);
        void ProcessZoneTree(const NJson::TJsonValue& zone, NSaas::TZone& parent);
        void ProcessZoneOptions(const NJson::TJsonValue& options, TSet<NJsonFormat::TEntity::EType>& types);
        void ProcessCsMap(const NJson::TJsonValue& csFactors, NSaas::TCSBlock& parent);
        void ProcessQsMap(const NJson::TJsonValue& qsFactors, NRTYServer::TMessage::TQSInfo& parent, EFactorsType factorsType);
        void ProcessAnnotations(const NJson::TJsonValue& annotations, NSaas::TAnnBlock& result);
        void ProcessGeo(const TString& name, const NJson::TJsonValue& geodata, NSaas::TGeoBlock& result);
        void ProcessDocOptions(const NJson::TJsonValue& options, NSaas::TDocument& document);
        void ProcessDocZone(const TString& name, const NJson::TJsonValue& zone, NSaas::TDocument& document);
        void ProcessQsFactorNames(const NJson::TJsonValue& qsFactorNames, NRTYServer::TMessage::TQSInfo& parent);
        void ProcessQsFactors(const NJson::TJsonValue& qsFactByKey, NRTYServer::TMessage::TQSInfo& parent, EFactorsType factorsType);
        void ProcessDoc(const NJson::TJsonValue& jsonDocument, TAction& target);
        void ParseType(const NJson::TJsonValue& type, TSet<NJsonFormat::TEntity::EType>& types) const;
        void ProcessAnnotations(const NJson::TJsonValue& sentences, NSaas::TDocument& document);
        void DeduceDocZoneType(const TString& name, const NJson::TJsonValue& value, TSet<NJsonFormat::TEntity::EType>& types) const;
        void DeduceZoneZoneType(const TString& name, const NJson::TJsonValue& value, TSet<NJsonFormat::TEntity::EType>& types) const;
    };

    class TProtobufDeserializer {
    public:
        void Deserialize(const NRTYServer::TMessage& source, TAction& target);
    private:
        typedef ::google::protobuf::RepeatedPtrField<NRTYServer::TAttribute> TProtobufAttributes;
        typedef ::google::protobuf::RepeatedPtrField<NRTYServer::TMessage::TDocument::TProperty> TProtobufProperties;
        typedef ::google::protobuf::RepeatedPtrField<NRTYServer::TZone> TProtobufZones;
    private:
        void ProcessSubZones(const TProtobufZones& zones, NSaas::TAbstractZone& abstractZone);
        void ProcessSearchAttributes(const TProtobufAttributes& attributes, NSaas::TAbstractZone& zone);
        void ProcessGroupAttributes(const TProtobufAttributes& attributes, NSaas::TAbstractZone& zone);
        void ProcessErfFactors(const NRTYServer::TMessage::TErfInfo& erf, NSaas::TAbstractZone& zone);
        void ProcessComplexFactors(const NRTYServer::TMessage::TDocument& document, NSaas::TDocument& zone);
        void ProcessFSProperties(const TProtobufProperties& properties, NSaas::TAbstractZone& zone);
        void ProcessProperties(const TProtobufProperties& properties, NSaas::TAbstractZone& zone);
        void ProcessSpecialKeys(const TProtobufProperties& properties, NSaas::TAbstractZone& zone);
        void ProcessTIProps(const TProtobufProperties& properties, NSaas::TAbstractZone& zone);
    };
}
