#pragma once

#include <balancer/kernel/fs/shared_file_rereader.h>
#include <balancer/kernel/log/errorlog.h>
#include <balancer/kernel/module/conn_descr.h>

#include <library/cpp/config/sax.h>
#include <library/cpp/proto_config/config.h>

#include <util/generic/ptr.h>
#include <util/generic/string.h>

namespace NModCookiePolicy {
    using namespace NSrvKernel;

    template <class TControls, class TControlsCfg=TControls>
    THolder<TControls> ParseControls(
        const TString& raw, TStringBuf fname, TStringBuf name, const TConnDescr& descr) noexcept
    {
        try {
            TStringInput sin(raw);
            auto rawCfg = NConfig::ConfigParser(sin);
            TControlsCfg cfg;
            NProtoConfig::ParseConfig(*rawCfg, cfg, [&] (
                const NProtoConfig::TKeyStack& ctx,
                const TString& key,
                NConfig::IConfig::IValue*)
            {
                auto NAME = name;
                LOG_ERROR(TLOG_ERR, descr,
                    "Unknown field in " << TString(fname).Quote() << " : " << key.Quote() << " at " << ctx);
            });
            return MakeHolder<TControls>(cfg);
        } catch (const yexception& e) {
            auto NAME = name;
            LOG_ERROR(TLOG_ERR, descr, "ReRead from " << TString(fname).Quote() << " failed: " << e.what());
            return nullptr;
        }
    }


    template <class TControls, class TControlsCfg=TControls>
    class TControlsReader {
    public:
        explicit TControlsReader(TString fname, IWorkerCtl& ctl)
            : File_(fname)
        {
            if (File_) {
                Reader_ = ctl.SharedFiles()->FileReReader(File_, TDuration::Seconds(1));
            }
        }

        [[nodiscard]]
        const TControls* ReRead(TStringBuf name, const TConnDescr& descr) noexcept {
            const auto& data = Reader_.Data();
            if (data.Id() == Data_.Id()) {
                return Controls_.Get();
            }
            Data_ = data;
            Controls_ = ParseControls<TControls, TControlsCfg>(Data_.Data(), File_, name, descr);
            return Controls_.Get();
        }

    private:
        TString File_;
        TSharedFileReReader Reader_;
        TSharedFileReReader::TData Data_;
        THolder<TControls> Controls_;
    };
}
