#ifndef FILESERVER_DATA_HXX
#define FILESERVER_DATA_HXX

#include <optional>
#include <list>
#include <unordered_map>
#include <string>
#include <chrono>
#include <mutex>
#include <shared_mutex>
#include <filesystem>
#include <thread>
#include <atomic>
#include <cstdint>

static const std::filesystem::path files_dir = "files";

struct Node {
    std::uint64_t id;
    std::string name;
    bool file, preview;
    std::shared_ptr<Node> parent;
    std::uint64_t size;
    std::list<std::shared_ptr<Node>> children;
};

struct User {
    std::uint64_t id;
    std::string name, password, tfa_secret;
    bool enabled, admin, tfa_enabled, tfa_mail;
    std::uint64_t next_node_id = 1;
    std::unordered_map<std::uint64_t, std::shared_ptr<Node>> nodes;
    std::filesystem::path user_dir;

    std::shared_mutex node_lock;
};

struct Token {
    using clock = std::chrono::steady_clock;
    static constexpr clock::duration token_lifetime = std::chrono::minutes{60};

    explicit Token(const std::shared_ptr<User> &user) : user(user) { refresh(); }

    void refresh() { expire = clock::now() + token_lifetime; }

    clock::time_point expire;
    std::shared_ptr<User> user, sudo_original_user{nullptr};
};

struct Config {
    std::string smtp_host, smtp_user, smtp_pass, smtp_from, admin_mail; // TODO: Send mail to admin on crash
    std::uint16_t smtp_port, server_port;
};

struct Data {
    static constexpr std::uint64_t current_version = 1;

    Data();
    ~Data();
    void load_config();
    void load();
    void validate();
    void save();
    void start_save_thread();
    void shutdown();

    Config config;

    std::uint64_t version = current_version, next_user_id = 0;
    std::unordered_map<std::uint64_t, std::shared_ptr<User>> users;
    std::unordered_map<std::string, std::shared_ptr<Token>> tokens;
    std::unordered_map<std::string, std::pair<std::uint64_t, Token::clock::time_point>> mail_otp;
    std::unordered_map<std::string, std::pair<std::uint64_t, Token::clock::time_point>> recovery_keys;

    std::thread save_thread;
    std::atomic_flag save_flag, shutdown_flag;
    std::shared_mutex user_lock, token_lock;
    std::mutex mail_otp_lock, recovery_lock;
};

#endif //FILESERVER_DATA_HXX
