#pragma once

#include <memory>
#include <string>
#include <functional>

class Socket
{
public:
    struct State
    {
        enum class ConnectStatus
        {
            UNSET,
            OK,
            FAILED
        };

        enum class BindStatus
        {
            UNSET,
            OK,
            FAILED
        };

        ConnectStatus mConnectStatus{ ConnectStatus::UNSET };
        BindStatus mBindStatus{ BindStatus::UNSET };
        std::string mErrorMessage;
        int mErrorCode{ 0 };
        std::string mBody;
    };

    Socket(const std::string& address, unsigned port);

    virtual ~Socket();

    std::string getAddress() const;

    unsigned getPort() const;

    const State& getState() const;

    virtual void respond(const std::string& message) = 0;

    virtual std::string recieve() = 0;

    virtual std::string send(const std::string& message) = 0;
protected:
    virtual void initialize() {};

    virtual void initializeForBind() {};

    virtual void doBind() {};

    virtual void doConnect() {};

    State mState;
    unsigned mPort{0};
    std::string mAddress;
};

using SocketPtr = std::unique_ptr<Socket>;
