#pragma once
#include "common.hpp"
#include "test.hpp"
#include "mkcert.hpp"
#include "hash.hpp"
#include "aio.hpp"


class SslCtx: public ConfigInst<size_t> {
    private:
        typedef struct {
            char host[MAX_SNI_LEN+1];
            ssl_ctx_t* ctx;
        } node_t;
        HashMap<node_t> cache;

    public:
        SslCtx(size_t);
        ~SslCtx();
        bool is_valid() const { return true; }

        ssl_ctx_t* get(const char*, const char*, size_t, const char*, size_t); ///< for given cn, cert, and key, return new ctx and cache it for this CN. Ctx must be freed.
        ssl_ctx_t* get(const char*); ///< for given CN return cache-hit, if any. Ctx must be freed.
};


class Wallet: public ConfigInst<char*> { // Goal is not to have to import a CA that can sign everything
    private:
        typedef struct {
            char host[MAX_SNI_LEN+1]; // prevent hash collisions:
            AioFileIn::Result* aio_result;
            // parsed #aio_result:
            const char* cert;
            size_t certlen;
            const char* key;
            size_t keylen;
        } data_t;
        HashMap<data_t> data;
        int dirfd;

        void load(const char*); ///< load cert~key file in #dirfd
        bool parse(data_t*); ///< parse aio result buf in cert and key
        tristate_t get(const char*, const char*&, size_t&, const char*&, size_t&); ///< #data lookup and defered parsing, TRI_TRUE: success, TRI_FALSE: error or no data (yet), TRI_NONE: not responsible for this host

    public:
        Wallet(const char*); ///< crawls given path and loads pre-defined cert~key files
        ~Wallet();
        bool is_valid() const { return dirfd != -1; }

        tristate_t get(const char*, SslCtx*, ssl_ctx_t*&); ///< sets ctx (if cert found) and caches it in given @see SslCtx, TRI_TRUE: success, TRI_FALSE: error or no data (yet), TRI_NONE: not responsible for this host
};