{ config, lib, pkgs, ... }:
let
  cfg = config.programs.rclone;
  targetName = "rclone";

  mkSystemdDependencyOption =
    { default, ... }: lib.mkOption {
      type = lib.types.attrsOf (lib.types.listOf lib.types.str);
      description = "The systemd services this sync depends on.";
      example = {
        secrets = [
          "sops-nix.service"
        ];
      };
      inherit default;
    };

  mkProvider =
    {
        displayName ? "Custom",
        secretsScript ? "",
        environment ? { },
        config ? { },
        options ? { },
        defaultOptions ? { }
    }:
      { ... }: {
        inherit
          displayName
          secretsScript
          environment
          config
        options
      ;
    };

  syncProviders = {
    nextcloud = mkProvider {};
    proton = mkProvider {};
    manual = mkProvider {};
  };

  mkSyncType = provider: lib.types.submodule (
    { config, name, ... }: {
      options = {
        autoStart = lib.mkOption {
          type = lib.types.bool;
          description = "Whether to start this sync automatically.";
          default = true;
        };

        providerOptions = lib.mkOption {
          description = "The options of the sync";
          type = lib.types.submodule { inherit (provider config) options; };
          default = { };
        };

        systemdDependencies = mkSystemdDependencyOption {
          default = cfg.systemdDependencies;
        };

        environment = lib.mkOption {
          type = lib.types.attrsOf lib.types.envVar;
          description = "The environment variables to pass to the service.";
          default = {};
        };

        secretsScript = lib.mkOption {
          type = lib.types.lines;
          description = "A script for loading secrets before launching the sync.";
          default = [];
        };

        config = lib.mkOption {
          type = lib.types.attrs;
          description = "The rclone config to use for creating the mount.";
          visible = false;
        };
      };

      config = {
        inherit (provider (lib.debug.traceVal config))
          environment
          secretsScript
          config
        ;
      };
    });
in {
  options = {
    programs.rclone = {
      enable = lib.mkEnableOption "rclone";

      systemdDependencies = mkSystemdDependencyOption {
        default = {};
      };

      configs = (builtins.mapAttrs
        (name: provider: lib.mkOption {
          type = lib.types.attrsOf (mkSyncType provider);
          description = "The ${(provider config).displayName} synchronizations to set up.";
          default = { };
        })
        syncProviders);
    };
  };

  config = {
    home.packages = lib.optional cfg.enable pkgs.rclone;

    systemd.user = lib.optionalAttrs cfg.enable {
      enable = true;

      services = {
        rclone = {
          Unit = {
            Description = "rclone Starter";
            Documentation = "man:rclone(1)";
          };

          Service = {
            Type = "simple";

            ExecStartPre =
              let
                script = pkgs.writeShellScriptBin "rclone-pre" ''
                  sleep 10
                '';
              in
                (lib.getExe script);

            ExecStart =
              let
                script = pkgs.writeShellScriptBin "rclone" ''
                  systemctl --user start rclone.target
                '';
              in
                (lib.getExe script);
          };
        };
      } // (
        lib.attrsets.concatMapAttrs
        (providerName: configs:
          lib.attrsets.concatMapAttrs
          (name: sync:
            let
              serviceName = "rclone-${providerName}-sync-${name}";
            in {
              ${serviceName} = {
                Unit = {
                  Description = "rclone sync service for ${name} at using ${providerName}";
                };

                Service = {
                  Environment = lib.mapAttrsToList
                    (key: val: (lib.escapeShellArg "${key}=${val}"))
                    sync.environment;

                  ExecStart =
                    let
                      script = pkgs.writeShellScriptBin serviceName ''
                        ${sync.secretsScript}
                        bash -c echo hello world
                      '';
                    in
                      (lib.getExe script);
                };

                Install = {
                  WantedBy = lib.optional sync.autoStart "${targetName}.target";
                  After = builtins.concatLists(builtins.attrValues sync.systemdDependencies);
                };
              };
            })
            configs)
        cfg.configs);

      targets.${targetName} = {
        Unit = {
          Description = "rclone Mounts";
          Documentation = "man:rclone(1)";
        };
      };
    };
  };
}