#pragma once

#include <cerrno>
#include <cstring>
#include <netdb.h>
#include <string>

namespace tw::net {

/**
 * A failed host lookup.
 *
 * Kept apart from NetworkError because getaddrinfo reports EAI_ codes, which
 * are their own mostly-negative space: sharing one enum would map a lookup
 * failure onto whichever errno happened to carry the same number.
 */
struct ResolutionError {
    int m_code;
    int m_errno;

public:
    /**
     * Only EAI_SYSTEM defers to errno, and errno will not have survived by the
     * time message() runs, so it is captured here.
     */
    static ResolutionError from_gai(int code) {
        return { code, errno };
    }

    std::string message() const {
        switch (m_code) {
            case EAI_NONAME:
                return "The host name is not known.";
            case EAI_AGAIN:
                return "The name server is unreachable or busy; the lookup may succeed later.";
            case EAI_FAIL:
                return "The name server returned a permanent failure.";
            case EAI_FAMILY:
                return "The requested address family is not supported.";
            case EAI_SERVICE:
                return "The requested port is not available for this socket type.";
            case EAI_MEMORY:
                return "Insufficient memory was available to complete the lookup.";
            case EAI_SYSTEM:
                return std::string(strerror(m_errno));
            default:
                return std::string(gai_strerror(m_code));
        }
    }
};

}
