#include <saas/rtyserver/indexer_core/merger_interfaces.h>
#include <saas/rtyserver/common/should_stop.h>
#include <saas/rtyserver/config/config.h>
#include <saas/rtyserver/config/merger_config.h>

#include <util/system/file_lock.h>

namespace {
    class TFileBasedLockPolicy: public IMergerLockPolicy {
    private:
        class TLock : public IMergerLock {
        public:
            inline TLock(TFileLock& lock)
                : Guard(lock)
            {
            }

            inline bool Acquired() const {
                return Guard.WasAcquired();
            }

        private:
            TTryGuard<TFileLock> Guard;
        };

    public:
        TFileBasedLockPolicy(const TRTYServerConfig& config)
            : Config(config)
        {
            if (Config.GetMergerConfig().IndexSwitchSystemLockFile) {
                FileLock = MakeHolder<TFileLock>(Config.GetMergerConfig().IndexSwitchSystemLockFile);
            }
        }

        IMergerLock::TPtr AcquireLock(const std::atomic<bool>* rigidStop) const {
            IMergerLock::TPtr lock = nullptr;
            while (FileLock && !ShouldStop(rigidStop)) {
                if (lock = TryAcquireLock()) {
                    break;
                }
                Sleep(TDuration::Seconds(1));
            }
            return lock;
        }

    private:
        IMergerLock::TPtr TryAcquireLock() const {
            CHECK_WITH_LOG(FileLock);
            auto lock = MakeHolder<TLock>(*FileLock);
            return lock->Acquired() ? std::move(lock) : nullptr;
        }

    private:
        const TRTYServerConfig& Config;
        THolder<TFileLock> FileLock;
    };

    class TOnStartLockPolicy: public TFileBasedLockPolicy {
    public:
        using TFileBasedLockPolicy::TFileBasedLockPolicy;

        IMergerLock::TPtr LockOnStart(IMergerTask* task, const std::atomic<bool>* rigidStop) const override {
            task->AddProgressInfo("Acquiring OnStart merger lock");
            return AcquireLock(rigidStop);
        }
        IMergerLock::TPtr LockOnFinish(IMergerTask* /*task*/, const std::atomic<bool>* /*rigidStop*/) const override {
            return nullptr;
        }
    };

    class TOnSwitchLockPolicy: public TFileBasedLockPolicy {
    public:
        using TFileBasedLockPolicy::TFileBasedLockPolicy;

        IMergerLock::TPtr LockOnStart(IMergerTask* /*task*/, const std::atomic<bool>* /*rigidStop*/) const override {
            return nullptr;
        }
        IMergerLock::TPtr LockOnFinish(IMergerTask* task, const std::atomic<bool>* rigidStop) const override {
            task->AddProgressInfo("Acquiring OnFinish merger lock");
            return AcquireLock(rigidStop);
        }
    };

    class TEmptyLockPolicy: public IMergerLockPolicy {
    public:
        TEmptyLockPolicy(const TRTYServerConfig& /*config*/) {}
        IMergerLock::TPtr LockOnStart(IMergerTask* /*task*/, const std::atomic<bool>* /*rigidStop*/) const override {
            return nullptr;
        }
        IMergerLock::TPtr LockOnFinish(IMergerTask* /*task*/, const std::atomic<bool>* /*rigidStop*/) const override {
            return nullptr;
        }
    };
}

IMergerLockPolicy::TFactory::TRegistrator<TEmptyLockPolicy> EmptyLockPolicy(NRTYServer::TMergerConfig::ELockPolicy::None);
IMergerLockPolicy::TFactory::TRegistrator<TOnStartLockPolicy> OnStartLockPolicy(NRTYServer::TMergerConfig::ELockPolicy::OnStart);
IMergerLockPolicy::TFactory::TRegistrator<TOnSwitchLockPolicy> OnSwitchLockPolicy(NRTYServer::TMergerConfig::ELockPolicy::OnSwitch);
