#pragma once

#include <arpa/inet.h>
#include <netdb.h>
#include <stdlib.h>
#include <string>
#include <unistd.h>

namespace slige_rpc {

struct Err {
    std::string msg;
};

template <typename T> class Res {
public:
    Res(T value)
    {
        this->value = value;
        this->holds_value = true;
    }
    Res(Err error)
    {
        this->error = error;
        this->holds_value = false;
    }
    auto is_ok() -> bool { return this->holds_value; }
    auto ok() -> T { return this->value; }
    auto err() -> Err { return this->error; }

private:
    bool holds_value;
    T value;
    Err error;
};

class BracketFinder {
public:
    BracketFinder()
        : layers(0)
    {
    }
    auto feed(int8_t c)
    {
        if (c == '{') {
            this->layers += 1;
        } else if (c == '}') {
            this->layers -= 1;
        }
    }
    auto bracket_closed() -> bool { return this->layers == 0; }

private:
    int layers;
};

struct Unit { };
struct Req { };

class BufferedWriter {
public:
    BufferedWriter(int fd)
        : fd(fd)
    {
    }
    BufferedWriter(const BufferedWriter&) = delete;
    BufferedWriter operator=(const BufferedWriter&) = delete;
    BufferedWriter(BufferedWriter&&) = delete;
    BufferedWriter operator=(BufferedWriter&&) = delete;
    ~BufferedWriter() { close(fd); }

    auto flush() -> Res<size_t>;
    auto write(uint8_t byte) -> Res<Unit>;
    auto write(std::string message) -> Res<Unit>;

private:
    static const size_t length = 1024;
    size_t occupied = 0;
    uint8_t buffer[length];
    int fd;
};

/// - load code
///     - program input
/// - run
/// - run debug
///     - fwamegwaph option
///     - code covewage option
/// - fetch fwamegwaph
///     - json string
/// - fetch code covewage
///     - json string
/// - fetch stack
///     - json string
template <typename Functor> class RpcServer {
public:
    RpcServer(Functor functor)
        : functor(functor) {};

    auto listen() -> Res<Unit>;

private:
    Functor functor;
};

};