#pragma once

#include "stats_counters.h"

#include <balancer/kernel/net/addr.h>

#include <util/datetime/base.h>
#include <util/network/ip.h>

namespace NSrvKernel::NDns {

    struct TResolveInfo {
        enum EType { // TODO (alexeylaptev) : remove
            GENERAL,
            NUMERIC,
        };

        TString Host;
        int Family = AF_UNSPEC;
        uint16_t Port = 0;
        EType Type = GENERAL;
    };

    class IResolver {
    public:
        virtual ~IResolver() = default;

        TErrorOr<TSockAddrInfo> Resolve(const TResolveInfo& info, bool onlyCache, TInstant deadline = TInstant::Max()) noexcept {
            return DoResolve(info, onlyCache, deadline);
        }

        void ResetCache() noexcept {
            DoResetCache();
        }

    private:
        virtual TErrorOr<TSockAddrInfo> DoResolve(const TResolveInfo& info, bool onlyCache, TInstant deadline) = 0;
        virtual void DoResetCache() = 0;
    };

    class TSimpleResolver : public IResolver {
    public:
        //! For direct call, not using IResolver
        static TErrorOr<TSockAddrInfo> Resolve(const TResolveInfo& info) {
            int flags = 0;
            if (info.Type == TResolveInfo::NUMERIC) {
                flags = AI_NUMERICHOST | AI_NUMERICSERV;
            }

            try {
                TNetworkAddress address(info.Host, info.Port, flags);
                TSockAddrInfo result;
                Y_PROPAGATE_ERROR(TSockAddr::FromAddrInfo(address).AssignTo(result.Addresses));
                return std::move(result);
            } Y_TRY_STORE(TNetworkResolutionError, yexception);
        }
    private:
        TErrorOr<TSockAddrInfo> DoResolve(const TResolveInfo& info, bool, TInstant) override {
            return Resolve(info);
        }

        void DoResetCache() override {}
    };

    using ResolverPtr = std::unique_ptr<IResolver>;
}
