#pragma once

#include "file_manager.h"

#include <library/cpp/coroutine/engine/impl.h>
#include <library/cpp/threading/hot_swap/hot_swap.h>
#include <library/cpp/threading/task_scheduler/task_scheduler.h>

#include <util/datetime/base.h>
#include <util/folder/path.h>
#include <util/generic/maybe.h>
#include <util/generic/ptr.h>
#include <util/generic/string.h>

#include <utility>

namespace NSrvKernel {
    namespace Internal {

        class TData : public TAtomicRefCount<TData> {
        public:
            TData() = default;

            size_t Id() const noexcept {
                return Id_;
            }

            const TString& Data() const noexcept {
                return Data_.GetOrElse(None_);
            }

            bool Exists() const noexcept {
                return !Data_.Empty();
            }

            void Update(TMaybe<TString> data) noexcept {
                Data_ = std::move(data);
                ++Id_;
            }

        private:
            ui64 Id_ = 0;
            TMaybe<TString> Data_;
            TString None_;
        };

        class TFileUpdater {
        public:
            explicit TFileUpdater(TString path);

            TFileUpdater(TString path, TData data);

        public:
            const TData& Data() const noexcept {
              return Data_;
            }

            TData& Data() noexcept {
                return Data_;
            }

            void Update() noexcept;

        private:
            bool UpdateFileStat();

            void UpdateFileData();

        private:
            TString Filename_;
            TData Data_;
            TFileStat Stat_;
        };

    }

    class TReReadTask : public TTaskScheduler::IRepeatedTask {
        using TData = Internal::TData;

    public:
        explicit TReReadTask(TString path);

        THotSwap<TData>::TPtr GetData();

        bool Process() override;

    private:
        Internal::TFileUpdater FileUpdater_;
        THotSwap<TData> DataStorage_;
    };

    class TSharedFileReReader : public TMoveOnly {
    public:
        using TData = Internal::TData;

        TSharedFileReReader() = default;

        explicit TSharedFileReReader(TIntrusivePtr<TReReadTask> reReadTask) noexcept;

        const TData& Data() const noexcept;

        bool Empty() const noexcept;

    private:
        TIntrusivePtr<TReReadTask> ReReadTask_ = nullptr;
        mutable TData Data_;
    };
}
