{
  config,
  lib,
  pkgs,
  ...
}: let
  cfg = config.xdg;
  username = "someone";
  fileType = lib.types.submodule {
    options = {
      text = lib.mkOption {
        type = lib.types.nullOr lib.types.lines;
        default = null;
      };
      source = lib.mkOption {
        type = lib.types.nullOr lib.types.path;
        default = null;
      };
      mutable = lib.mkOption {
        type = lib.types.bool;
        default = false;
        description = "If true, copy the file instead of symlinking, allowing the application to modify it";
      };
    };
  };
  userOpts = _: {
    options = {
      configFiles = lib.mkOption {
        type = lib.types.attrsOf fileType;
        default = {};
      };
      cacheFiles = lib.mkOption {
        type = lib.types.attrsOf fileType;
        default = {};
      };
      dataFiles = lib.mkOption {
        type = lib.types.attrsOf fileType;
        default = {};
      };
      stateFiles = lib.mkOption {
        type = lib.types.attrsOf fileType;
        default = {};
      };
      homeFiles = lib.mkOption {
        type = lib.types.attrsOf fileType;
        default = {};
      };
    };
  };

  mkLinkScript = baseDir: name: file: let
    target =
      if file.text != null
      then pkgs.writeText name file.text
      else file.source;
    fullPath = "${baseDir}/${name}";
    parentDir = builtins.dirOf fullPath;
  in
    if file.mutable
    then ''
      mkdir -p "${parentDir}"
      if [ -L "${fullPath}" ]; then
        # Replace symlink with a copy
        rm -f "${fullPath}"
        cp "${target}" "${fullPath}"
        chmod +w "${fullPath}"
      elif [ -e "${fullPath}" ]; then
        :
      else
        cp "${target}" "${fullPath}"
        chmod +w "${fullPath}"
      fi
    ''
    else ''
      mkdir -p "${parentDir}"
      if [ -L "${fullPath}" ]; then
        current_target=$(readlink "${fullPath}")
        if [ "$current_target" != "${target}" ]; then
          rm -f "${fullPath}"
          ln -s "${target}" "${fullPath}"
        fi
      elif [ -e "${fullPath}" ]; then
        rm -f "${fullPath}"
        ln -s "${target}" "${fullPath}"
      else
        ln -s "${target}" "${fullPath}"
      fi
    '';
in {
  options = {
    users.users = lib.mkOption {type = lib.types.attrsOf (lib.types.submodule userOpts);};
    home = {
      homeDirectory = lib.mkOption {
        type = lib.types.path;
        default = "/home/${username}";
      };
      file = lib.mkOption {
        type = lib.types.attrsOf fileType;
        default = {};
      };
    };
    xdg = {
      configHome = lib.mkOption {
        type = lib.types.path;
        default = "/home/${username}/.config";
      };
      cacheHome = lib.mkOption {
        type = lib.types.path;
        default = "/home/${username}/.cache";
      };
      dataHome = lib.mkOption {
        type = lib.types.path;
        default = "/home/${username}/.local/share";
      };
      stateHome = lib.mkOption {
        type = lib.types.path;
        default = "/home/${username}/.local/state";
      };
      runtimeDir = lib.mkOption {
        type = lib.types.str;
        default = "/run/user/1000";
      };
      configFile = lib.mkOption {
        type = lib.types.attrsOf fileType;
        default = {};
      };
      cacheFile = lib.mkOption {
        type = lib.types.attrsOf fileType;
        default = {};
      };
      dataFile = lib.mkOption {
        type = lib.types.attrsOf fileType;
        default = {};
      };
      stateFile = lib.mkOption {
        type = lib.types.attrsOf fileType;
        default = {};
      };
    };
  };

  config = {
    users.users.${username} = {
      configFiles = cfg.configFile;
      cacheFiles = cfg.cacheFile;
      dataFiles = cfg.dataFile;
      stateFiles = cfg.stateFile;
      homeFiles = config.home.file;
    };

    environment.sessionVariables = {
      XDG_CONFIG_HOME = cfg.configHome;
      XDG_CACHE_HOME = cfg.cacheHome;
      XDG_DATA_HOME = cfg.dataHome;
      XDG_STATE_HOME = cfg.stateHome;
    };

    system.activationScripts.xdgUserFiles = lib.stringAfter ["users"] ''
      ${lib.concatStringsSep "\n" (
        lib.flatten (
          lib.mapAttrsToList (
            user: userCfg:
              (lib.mapAttrsToList (mkLinkScript cfg.configHome) userCfg.configFiles)
              ++ (lib.mapAttrsToList (mkLinkScript cfg.cacheHome) userCfg.cacheFiles)
              ++ (lib.mapAttrsToList (mkLinkScript cfg.dataHome) userCfg.dataFiles)
              ++ (lib.mapAttrsToList (mkLinkScript cfg.stateHome) userCfg.stateFiles)
              ++ (lib.mapAttrsToList (mkLinkScript config.home.homeDirectory) userCfg.homeFiles)
          )
          config.users.users
        )
      )}
    '';
  };
}
