# My own module with nicer syntax for impernanence 
{ lib, config, ... }:
let cfg = config.satellite.persistence;
in
{
  options.satellite.persistence = {
    enable = lib.mkEnableOption "satellite persitence";

    at = lib.mkOption {
      default = { };
      description = "Record of persistent locations (eg: /persist)";
      type = lib.types.attrsOf (lib.types.submodule (_: {
        options = {
          path = lib.mkOption {
            type = lib.types.str;
            example = "/persist";
            default = null;
            description = "The location to store the files described in this record";
          };

          prefixDirectories = lib.mkOption {
            type = lib.types.bool;
            default = true;
            example = false;
            description = "Whether to enable gnu/stow type prefix directories";
          };

          apps = lib.mkOption {
            default = { };
            description = "The apps to be stores in this persistent location";
            type = lib.types.attrsOf (lib.types.submodule (_: {
              options = {
                files = lib.mkOption {
                  type = lib.types.listOf lib.types.str;
                  default = [ ];
                  example = [ ".screenrc" ];
                  description = ''
                    A list of files in your home directory you want to
                    link to persistent storage. Allows both absolute paths
                    and paths relative to the home directory. .
                  '';
                };

                directories = lib.mkOption {
                  default = [ ];
                  description = "Modified version of home.persistence.*.directories which takes in absolute paths";
                  type = lib.types.listOf (lib.types.either lib.types.str (lib.types.submodule {
                    options = {
                      directory = lib.mkOption {
                        type = lib.types.str;
                        default = null;
                        description = "The directory path to be linked.";
                      };

                      method = lib.mkOption {
                        type = lib.types.enum [ "bindfs" "symlink" ];
                        default = "symlink";
                        description = ''
                          The linking method that should be used for this
                          directory. bindfs is the default and works for most use
                          cases, however some programs may behave better with
                          symlinks.
                        '';
                      };
                    };
                  }));
                };
              };
            }));
          };
        };
      }));
    };
  };

  config =
    let
      makeLocation = location:
        let
          processPath = appName: value:
            let
              suffix = "${lib.strings.removePrefix "${config.home.homeDirectory}/" (builtins.toString value)}";
              prefix = if location.prefixDirectories then "${appName}/" else "";
            in
            # lib.debug.traceSeq "\nProcessing path at location ${location.path} and app ${appName} from original path ${value} to ${prefix + suffix}" 
            (prefix + suffix);

          mkDirectory = appName: directory:
            if builtins.isAttrs directory then {
              method = directory.method;
              directory = processPath appName directory.directory;
            }
            else processPath appName directory;

          mkAppDirectory = appName: app: builtins.map (mkDirectory appName) app.directories;
          mkAppFiles = appName: app: builtins.map (processPath appName) app.files;
        in
        lib.attrsets.nameValuePair (location.path + config.home.homeDirectory) {
          removePrefixDirectory = location.prefixDirectories;
          allowOther = true;
          directories = lib.lists.flatten
            (lib.attrsets.mapAttrsToList mkAppDirectory location.apps);

          files = lib.lists.flatten
            (lib.attrsets.mapAttrsToList mkAppFiles location.apps);
        };
    in
    lib.mkIf cfg.enable {
      home.persistence = lib.attrsets.mapAttrs' (_: makeLocation) cfg.at;
    };
}