{ pkgs
, lib
, config
, ... }: with lib; let
  cfg = config.global.fs;
in {
  imports = [
    ./alert.nix
    ./split.nix
    ./replication.nix
  ];

  # -o ashift=12
  # -O encryption=on -O keyformat=passphrase -O keylocation=prompt
  # -O compression=on -O mountpoint=none -O xattr=sa -O acltype=posixacl
  options.global.fs.zfs = {
    alert = {
      zed = mkEnableOption "zfs event alerts" // { default = true; };
      swraid = mkEnableOption "software raid alerts" // { default = true; };
      secret = mkOption {
        type = with types; nullOr str;
        default = null;
        description = "path to alert secrets";
      };
    };

    persist = mkOption {
      type = with types; str;
      default = cfg.store;
      description = ''
        pool for persist dataset
        defaults to nix store dataset
      '';
    };
    mountpoints = mkOption {
      type = with types; attrsOf str;
      description = "zfs dataset mountpoints";
    };
    externalStore = mkEnableOption "external nix store filesystem";

    split = {
      enable = mkEnableOption "zfs state with split nix store";
      mdProg = mkOption {
        type = with types; str;
        default = "/usr/bin/true";
        description = "mdadm PROGRAM config value";
      };
      secret = mkOption {
        type = with types; str;
        description = "UUID of secret filesystem";
      };
      store = mkOption {
        type = with types; str;
        description = "UUID of store filesystem";
      };
    };

    replication = {
      enable = mkEnableOption "zfs replication to remote";
      remote = mkOption {
        type = with types; str;
        description = "remote host as replication destination";
      };
      port = mkOption {
        type = with types; port;
        description = "ssh port of replication target";
        default = 22;
      };
      datasets = mkOption {
        type = with types; listOf str;
        default = [ "persist" "service" "storage" ];
        description = "list of filesystems to perform replication for";
      };
      sendOptions = mkOption {
        type = with types; str;
        default = "w";
        description = "send options for all datasets";
      };
    };
  };

  config = mkIf (cfg.type == "zfs") {
    fileSystems = (mapAttrs (path: dataset: {
      device = "${cfg.zfs.persist}/${dataset}";
      fsType = "zfs";
      # required by impermanence
      neededForBoot = true;
    }) cfg.zfs.mountpoints) // {
      "/nix" = (if !cfg.zfs.externalStore then
        { device = "${cfg.store}/nix";
          fsType = "zfs";
        } else
        { inherit (cfg.external) device fsType options; });
    };
    global.fs.zfs.mountpoints."/nix/persist" = "persist";

    services.zfs.trim.enable = true;
    services.zfs.autoSnapshot.enable = true;
    services.zfs.autoScrub.enable = true;
    boot.zfs.devNodes = mkDefault "/dev/disk/by-partuuid";
    #boot.kernelPackages = mkDefault config.boot.zfs.package.latestCompatibleLinuxPackages;
    global.kernel.lts = mkDefault true;
  };
}
