/*
  ISC License

  Copyright (c) 2026, Antonio SJ Musumeci <trapexit@spawn.link>

  Permission to use, copy, modify, and/or distribute this software for any
  purpose with or without fee is hereby granted, provided that the above
  copyright notice and this permission notice appear in all copies.

  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#pragma once

#include "branches.hpp"
#include "category.hpp"
#include "config_cachefiles.hpp"
#include "config_debug.hpp"
#include "config_dummy.hpp"
#include "config_flushonclose.hpp"
#include "config_follow_symlinks.hpp"
#include "config_inodecalc.hpp"
#include "config_link_exdev.hpp"
#include "config_log_file.hpp"
#include "config_moveonenospc.hpp"
#include "config_nfsopenhack.hpp"
#include "config_noforget.hpp"
#include "config_pagesize.hpp"
#include "config_passthrough_io.hpp"
#include "config_pid.hpp"
#include "config_proxy_ioprio.hpp"
#include "config_rename_exdev.hpp"
#include "config_set.hpp"
#include "config_statfs.hpp"
#include "config_statfsignore.hpp"
#include "config_xattr.hpp"
#include "enum.hpp"
#include "errno.hpp"
#include "fs_path.hpp"
#include "funcs.hpp"
#include "fuse_cfg.hpp"
#include "fuse_readdir.hpp"
#include "policy.hpp"
#include "tofrom_ref.hpp"
#include "tofrom_wrapper.hpp"
#include "syslog.hpp"

#include "fuse.h"

#include "base_types.h"

#include <map>
#include <memory>
#include <string>
#include <vector>

#include <sys/stat.h>

typedef ToFromWrapper<bool>                 ConfigBOOL;
typedef ToFromWrapper<u64>                  ConfigU64;
typedef ToFromWrapper<s64>                  ConfigS64;
typedef ToFromWrapper<int>                  ConfigINT;
typedef ToFromWrapper<std::string>          ConfigSTR;
typedef ToFromWrapper<fs::path>             ConfigPath;
typedef std::map<std::string,ToFromString*> Str2TFStrMap;
typedef ROToFromWrapper<std::string>        ConfigROSTR;


class Config
{
public:
  struct Err
  {
    int err;
    std::string str;

    std::string to_string() const;
  };

  typedef std::vector<Err> ErrVec;

public:
  ErrVec errs;

public:
  class CfgConfigFile : public ToFromString
  {
  private:
    fs::path  _cfg_file;
    static thread_local int _depth;

  public:
    CfgConfigFile();

  public:
    int from_string(const std::string_view s_) final;
    std::string to_string(void) const final;
  };

public:
  Config();

public:
  ConfigBOOL     allow_idmap;
  ConfigBOOL     async_read;
  Branches       branches;
  ConfigU64      branches_mount_timeout;
  ConfigBOOL     branches_mount_timeout_fail;
  ConfigU64      cache_attr;
  ConfigU64      cache_entry;
  CacheFiles     cache_files;
  ConfigSet      cache_files_process_names;
  ConfigU64      cache_negative_entry;
  ConfigBOOL     cache_readdir;
  ConfigU64      cache_statfs;
  ConfigBOOL     cache_symlinks;
  ConfigBOOL     cache_writeback;
  Categories     category;
  CfgConfigFile  config_file;
  ConfigBOOL     direct_io_allow_mmap;
  ConfigBOOL     dropcacheonclose;
  ConfigBOOL     export_support;
  FlushOnClose   flushonclose;
  FollowSymlinks follow_symlinks;
  ConfigSTR      fsname;
  Funcs          func;
  ConfigPageSize fuse_msg_size;
  ConfigBOOL     handle_killpriv;
  ConfigBOOL     handle_killpriv_v2;
  ConfigBOOL     ignorepponrename;
  InodeCalc      inodecalc;
  ConfigBOOL     kernel_permissions_check;
  ConfigBOOL     lazy_umount_mountpoint;
  ConfigBOOL     link_cow;
  LinkEXDEV      link_exdev;
  LogFile        log_file;
  TFSRef<u64>    minfreespace;
  fs::path       mountpoint;
  MoveOnENOSPC   moveonenospc;
  NFSOpenHack    nfsopenhack;
  ConfigBOOL     nullrw;
  ConfigBOOL     parallel_direct_writes;
  PassthroughIO  passthrough_io;
  TFSRef<int>    passthrough_max_stack_depth;
  ConfigGetPid   pid;
  TFSRef<std::string> pin_threads;
  ConfigBOOL     posix_acl;
  TFSRef<int>    process_thread_count;
  TFSRef<int>    process_thread_queue_depth;
  ProxyIOPrio    proxy_ioprio;
  TFSRef<int>    read_thread_count;
  ConfigU64      readahead;
  FUSE::ReadDir  readdir;
  RenameEXDEV    rename_exdev;
  ConfigINT      scheduling_priority;
  ConfigBOOL     security_capability;
  StatFS         statfs;
  StatFSIgnore   statfs_ignore;
  ConfigBOOL     symlinkify;
  ConfigS64      symlinkify_timeout;
  XAttr          xattr;

private:
  TFSRef<int>      _congestion_threshold;
  Debug            _debug;
  CfgDummy         _dummy;
  TFSRef<s64>      _gid;
  TFSRef<int>      _max_background;
  TFSRef<fs::path> _mount;
  TFSRef<fs::path> _mountpoint;
  CfgNoforget      _never_forget_nodes;
  CfgNoforget      _noforget;
  TFSRef<s64>      _remember;
  TFSRef<s64>      _remember_nodes;
  SrcMounts        _srcmounts;
  TFSRef<int>      _threads;
  TFSRef<s64>      _uid;
  TFSRef<s64>      _umask;
  ConfigROSTR      _version;

private:
  bool _initialized;

public:
  void finish_initializing();

public:
  friend std::ostream& operator<<(std::ostream &s,
                                  const Config &c);

public:
  bool has_key(const std::string &key) const;
  ssize_t keys_listxattr(char *list, size_t size) const;
  ssize_t keys_listxattr_size() const;
  const Str2TFStrMap& get_map() const { return _map; }

public:
  int get(const std::string &key, std::string *val) const;
  int set(const std::string &key, const std::string &val);
  int set(const std::string &kv);

public:
  int from_stream(std::istream &istrm);
  int from_file(const std::string &filepath);

public:
  static bool is_rootdir(const fs::path &fusepath);
  static bool is_ctrl_file(const fs::path &fusepath);
  static bool is_mergerfs_xattr(const char *attrname);
  static bool is_cmd_xattr(const std::string_view &attrname);
  static std::string_view prune_ctrl_xattr(const std::string_view s);
  static std::string_view prune_cmd_xattr(const std::string_view &s);

private:
  Str2TFStrMap _map;
};

extern Config cfg;
