#pragma once

#include <saas/rtyserver/config/config.h>
#include <saas/rtyserver/config/repair_config.h>
#include <saas/rtyserver/index_storage/index_storage.h>
#include <saas/rtyserver/modifier/document_modifier.h>
#include <saas/rtyserver/indexer_disk/indexer_manager.h>
#include <saas/util/queue.h>
#include <util/thread/factory.h>

class TIndexRepair;

class TRepairerTask : public IObjectInQueue {
    TString TaskDir;
    TIndexRepair& Owner;
public:
    TRepairerTask(TString taskDir, TIndexRepair& owner);

    TString GetTaskDir() {
        return TaskDir;
    }

private:
    bool FixByLog(const TString& tempDir);

    virtual void Process(void* ThreadSpecificResource);
};

class TIndexRepair: public IMessageProcessor {
    TRTYMtpQueue RepairTasks;
    TMutex Mutex;
    bool IsStarted;
    std::atomic<bool> RigidStop;
    TVector<THolder<TRepairerTask>> TasksBuffer;
    TAtomic TasksExecuted;

public:
    TIndexStorage& IndexStorage;
    TIndexerManager& DiskIndexManager;
    const TRTYServerConfig& Config;
    TDocumentModifier& Modifier;

public:
    TIndexRepair(TIndexStorage& indexStorage, TIndexerManager& diskIndexManager, const TRTYServerConfig& config, TDocumentModifier& modifier)
        : RepairTasks("IndexRepair")
        , IsStarted(false)
        , RigidStop(false)
        , TasksExecuted(0)
        , IndexStorage(indexStorage)
        , DiskIndexManager(diskIndexManager)
        , Config(config)
        , Modifier(modifier)
    {
        RegisterGlobalMessageProcessor(this);
    }

    virtual ~TIndexRepair() {
        UnregisterGlobalMessageProcessor(this);
        VERIFY_WITH_LOG(!IsStarted, "Incorrect repairer closing");
    }

    virtual TString Name() const {
        return "Repairer";
    }

    virtual bool Process(IMessage* message);

    TDocumentModifier& GetModifier() {
        return Modifier;
    }


    bool IsRepairing() const {
        return Config.GetRepairConfig().Enabled && (TasksExecuted > 0);
    }

    void Wait() const {
        while (IsRepairing())
            Sleep(TDuration::Seconds(1));
    }

    bool Start();

    void Stop(bool rigidStop) {
        TGuard<TMutex> g(Mutex);
        NOTICE_LOG << "Repair's threads stopping ..." << Endl;
        IsStarted = false;
        RigidStop = rigidStop;
        RepairTasks.Stop();
        NOTICE_LOG << "Repair's threads stopping ... OK" << Endl;
    }

    const bool& GetIsStarted() const {
        return IsStarted;
    }

    const std::atomic<bool>* GetRigidStopSignal() const {
        return &RigidStop;
    }

    void OnCreateTask(TRepairerTask* /*task*/) {
        AtomicIncrement(TasksExecuted);
    }

    void OnEndTask(TRepairerTask* /*task*/) {
        AtomicDecrement(TasksExecuted);
    }
};
