#pragma once
#ifndef MRPC_GEN_H
#define MRPC_GEN_H

#include <memory>
#include <string>
#include <vector>
#include <optional>
#include <cstdint>
#include <cmath>
#include <corvusoft/restbed/byte.hpp>
#define RAPIDJSON_HAS_STDSTRING 1
#include <rapidjson/stringbuffer.h>
#include <rapidjson/writer.h>
#include <rapidjson/document.h>

namespace restbed {
    class Resource;
    class Session;
}

namespace mrpc {
using MRPCJWriter = rapidjson::Writer<rapidjson::StringBuffer>;

template<typename T>
struct Response;
struct LoginResponse;
struct Session;
struct UserInfo;
struct Node;
struct CreateNodeInfo;
struct ZipInfo;
struct PathSegment;


template<typename T>
struct Response {
    std::optional<std::string> e;
    std::optional<T> o;

    MRPCJWriter& operator >>(MRPCJWriter&) const;
    Response& operator <<(const rapidjson::Value&);
};
struct LoginResponse {
    bool otp_needed;
    std::optional<std::string> token;

    MRPCJWriter& operator >>(MRPCJWriter&) const;
    LoginResponse& operator <<(const rapidjson::Value&);
};
struct Session {
    std::string name;
    bool tfa_enabled;
    bool admin;
    bool sudo;

    MRPCJWriter& operator >>(MRPCJWriter&) const;
    Session& operator <<(const rapidjson::Value&);
};
struct UserInfo {
    std::uint64_t id;
    std::string name;
    bool tfa;
    bool admin;
    bool enabled;

    MRPCJWriter& operator >>(MRPCJWriter&) const;
    UserInfo& operator <<(const rapidjson::Value&);
};
struct Node {
    std::uint64_t id;
    std::string name;
    bool file;
    bool preview;
    std::optional<std::uint64_t> parent;
    std::optional<std::uint64_t> size;
    std::optional<std::vector<Node>> children;

    MRPCJWriter& operator >>(MRPCJWriter&) const;
    Node& operator <<(const rapidjson::Value&);
};
struct CreateNodeInfo {
    std::uint64_t id;
    bool exists;
    bool file;

    MRPCJWriter& operator >>(MRPCJWriter&) const;
    CreateNodeInfo& operator <<(const rapidjson::Value&);
};
struct ZipInfo {
    bool done;
    std::uint64_t progress;
    std::uint64_t total;

    MRPCJWriter& operator >>(MRPCJWriter&) const;
    ZipInfo& operator <<(const rapidjson::Value&);
};
struct PathSegment {
    std::string name;
    std::optional<std::uint64_t> id;

    MRPCJWriter& operator >>(MRPCJWriter&) const;
    PathSegment& operator <<(const rapidjson::Value&);
};

struct MRPCStreamImpl {
    void close() const noexcept;
    bool is_open() const noexcept;
protected:
    explicit MRPCStreamImpl(const std::shared_ptr<restbed::Session> &conn);
    std::shared_ptr<restbed::Session> conn;
};

template<typename T>
struct MRPCStream final : MRPCStreamImpl {
    explicit MRPCStream(const std::shared_ptr<restbed::Session> &conn) : MRPCStreamImpl(conn) {}
    void send(const T &v) const noexcept;
};

template struct MRPCStream<std::string>;

struct MRPCServer {
    MRPCServer() = delete;
    explicit MRPCServer(std::shared_ptr<restbed::Resource>&);
private:
    virtual std::optional<std::string> Auth_signup(std::string &&username, std::string &&password) = 0;
    virtual Response<LoginResponse> Auth_login(std::string &&username, std::string &&password, std::optional<std::string> &&otp) = 0;
    virtual void Auth_send_recovery_key(std::string &&username) = 0;
    virtual std::optional<std::string> Auth_reset_password(std::string &&key, std::string &&password) = 0;
    virtual std::optional<std::string> Auth_change_password(std::string &&token, std::string &&old_pw, std::string &&new_pw) = 0;
    virtual void Auth_logout(std::string &&token) = 0;
    virtual std::optional<std::string> Auth_logout_all(std::string &&token) = 0;
    virtual std::optional<std::string> Auth_tfa_setup_mail(std::string &&token) = 0;
    virtual Response<std::string> Auth_tfa_setup_totp(std::string &&token) = 0;
    virtual std::optional<std::string> Auth_tfa_complete(std::string &&token, std::string &&otp) = 0;
    virtual std::optional<std::string> Auth_tfa_disable(std::string &&token) = 0;
    virtual std::optional<std::string> Auth_delete_user(std::string &&token) = 0;
    virtual Response<Session> Auth_session_info(std::string &&token) = 0;
    virtual Response<std::vector<UserInfo>> Admin_list_users(std::string &&token) = 0;
    virtual std::optional<std::string> Admin_delete_user(std::string &&token, std::uint64_t &&user) = 0;
    virtual std::optional<std::string> Admin_logout(std::string &&token, std::uint64_t &&user) = 0;
    virtual std::optional<std::string> Admin_disable_tfa(std::string &&token, std::uint64_t &&user) = 0;
    virtual std::optional<std::string> Admin_set_admin(std::string &&token, std::uint64_t &&user, bool &&admin) = 0;
    virtual std::optional<std::string> Admin_set_enabled(std::string &&token, std::uint64_t &&user, bool &&enabled) = 0;
    virtual std::optional<std::string> Admin_sudo(std::string &&token, std::uint64_t &&user) = 0;
    virtual std::optional<std::string> Admin_unsudo(std::string &&token) = 0;
    virtual std::optional<std::string> Admin_shutdown(std::string &&token) = 0;
    virtual Response<Node> FS_get_node(std::string &&token, std::uint64_t &&node) = 0;
    virtual Response<std::vector<PathSegment>> FS_get_path(std::string &&token, std::uint64_t &&node) = 0;
    virtual Response<std::uint64_t> FS_get_nodes_size(std::string &&token, std::vector<std::uint64_t> &&nodes) = 0;
    virtual Response<CreateNodeInfo> FS_create_node(std::string &&token, bool &&file, std::uint64_t &&parent, std::string &&name) = 0;
    virtual std::optional<std::string> FS_move_nodes(std::string &&token, std::vector<std::uint64_t> &&nodes, std::uint64_t &&parent) = 0;
    virtual void FS_delete_nodes(std::string &&token, std::vector<std::uint64_t> &&nodes, MRPCStream<std::string>&&) = 0;
    virtual Response<std::string> FS_download_preview(std::string &&token, std::uint64_t &&node) = 0;
    virtual Response<std::string> FS_get_mime(std::string &&token, std::uint64_t &&node) = 0;

    virtual void msg_handler(std::shared_ptr<restbed::Session>, const restbed::Bytes&) final;
};
}

#endif // MRPC_GEN_H
