#pragma once

#include <balancer/kernel/client_request/backend_config.cfgproto.pb.h>
#include <balancer/kernel/net/sockops.h>
#include <balancer/kernel/ssl/ssl_client_ctx_storage.h>


namespace NSrvKernel {

struct THttpsSettings : public NSrvKernelProto::THttpsParams {
    THttpsSettings(const THttpsParams& params)
            : THttpsParams(params)
            , SslClientContext(GetSslClientContext(ciphers().data(), verify_depth(), ca_file()))
    {
    }

    TAtomicSharedPtr<const TSslClientContext> SslClientContext;
};

class TBackendConfig: public NSrvKernelProto::TBackendConfig {
  public:
    TBackendConfig() = default;
    explicit TBackendConfig(const TProto& message): NSrvKernelProto::TBackendConfig(message) {
        if (use_only_ipv4() || use_only_ipv6()) {
            Y_ENSURE_EX(!(use_only_ipv4() && use_only_ipv6()),
                        TConfigParseError() << "use_only_ipv4 and use_only_ipv6 cannot be both enabled");
            Family_ = use_only_ipv4() ? AF_INET : AF_INET6;
        }

        if (has_tcp_keep_cnt()) {
            TcpKeepalive_.Cnt = tcp_keep_cnt();
        }

        if (has_tcp_keep_idle()) {
            TcpKeepalive_.Idle = tcp_keep_idle();
        }

        if (has_tcp_keep_intvl()) {
            TcpKeepalive_.Intvl = tcp_keep_intvl();
        }

        if (Has_sock_inbufsize()) {
            SockBufSize_.Rcv = _sock_inbufsize();
        }

        if (Has_sock_outbufsize()) {
            SockBufSize_.Snd = _sock_outbufsize();
        }

        if (!has_need_resolve()) {
            set_need_resolve(true);
        }

        if (has_https_settings()) {
            if (https_settings().ca_file().empty()) {
                ythrow TConfigParseError() << "ca_file is required for https_settings in proxy";
            }

            if (https_settings().verify_depth() < 0) {
                ythrow TConfigParseError() << "verify depth cannot be negative in https_settings in proxy";
            }

            if (!https_settings().has_sni_on() && https_settings().sni_host()) {
                https_settings().set_sni_on(true);
            }

            HttpsSettings_.ConstructInPlace(https_settings());
        }
    }

    int GetFamily() const {
        return Family_;
    }

    const TTcpKeepalive& GetTcpKeepalive() const {
        return TcpKeepalive_;
    }

    const TSockBufSize& GetSockBufSize() const {
        return SockBufSize_;
    }

    const TMaybe<TSockAddrInfo>& GetCachedAddr() const {
        return CachedAddr_;
    }

    const TMaybe<THttpsSettings>& GetHttpsSettings() const {
        return HttpsSettings_;
    }

    TError FillCachedAddr() {
        TSockAddr addr;
        Y_PROPAGATE_ERROR(TSockAddr::FromIpPort(cached_ip(), port()).AssignTo(addr));
        CachedAddr_ = TSockAddrInfo{{addr}};
        return {};
    }

  private:
    int Family_ = AF_UNSPEC;
    TTcpKeepalive TcpKeepalive_ {
            .Cnt = 9,
            .Idle=1,
            .Intvl=1
    };
    TSockBufSize SockBufSize_;
    TMaybe<TSockAddrInfo> CachedAddr_;
    TMaybe<THttpsSettings> HttpsSettings_;
};
} // namespace NSrvKernel
