#pragma once

#include <yandex/maps/wiki/tasks/task_logger.h>

#include <memory>

namespace maps::wiki::exporter {

using tasks::Severity;

/**
 * Export may be called either as a grinder task or from command line.
 * In the first case grinder task log should be written to PG task table,
 * but in the second - it should not.
 * Logger interface is a quick and dirty solution to hide this dependency
 */

class LoggerProxy {
public:
    LoggerProxy(
        std::shared_ptr<tasks::TaskPgLogger> pgLoggerPtr,
        tasks::Severity severity)
    {
        if (pgLoggerPtr) {
            msg = std::unique_ptr<tasks::Message>(
                    new tasks::Message(*pgLoggerPtr, severity));
        }
    }

    LoggerProxy(LoggerProxy&&) = default;
    LoggerProxy& operator=(LoggerProxy&&) = default;

    template <class T>
    LoggerProxy& operator<<(const T& val)
    {
        if (msg)
            *msg << val;
        return *this;
    }

private:
    std::unique_ptr<tasks::Message> msg;
};


class Logger {
public:
    Logger() {}
    virtual ~Logger() = default;

    Logger(const Logger&) = delete;
    Logger& operator=(const Logger&) = delete;
    Logger(Logger&&) = default;
    Logger& operator=(Logger&&) = default;

    virtual LoggerProxy logInfo() = 0;
    virtual LoggerProxy logWarn() = 0;
    virtual LoggerProxy logError() = 0;
};


class DbLogger : public Logger {
public:
    explicit DbLogger(std::shared_ptr<tasks::TaskPgLogger> taskPgLoggerPtr)
        : taskPgLoggerPtr_(taskPgLoggerPtr)
    {}

    virtual ~DbLogger() = default;

    LoggerProxy logInfo() override
    {
        return LoggerProxy(taskPgLoggerPtr_, Severity::Info);
    }

    LoggerProxy logWarn() override
    {
        return LoggerProxy(taskPgLoggerPtr_, Severity::Warn);
    }

    LoggerProxy logError() override
    {
        return LoggerProxy(taskPgLoggerPtr_, Severity::Error);
    }

private:
    std::shared_ptr<tasks::TaskPgLogger> taskPgLoggerPtr_;
};


class DevNullLogger : public Logger {
public:
    DevNullLogger() {}
    virtual ~DevNullLogger() = default;

    LoggerProxy logInfo() override
    {
        return LoggerProxy(nullptr, Severity::Info);
    }

    LoggerProxy logWarn() override
    {
        return LoggerProxy(nullptr, Severity::Warn);
    }

    LoggerProxy logError() override
    {
        return LoggerProxy(nullptr, Severity::Error);
    }
};

} // namespace maps::wiki::exporter
