{
  config,
  lib,
  ...
}:
with lib; let
  cfg = config.custom.services.syncthing;
in {
  # https://github.com/syncthing/syncthing
  # https://wiki.nixos.org/wiki/Syncthing
  # https://docs.syncthing.net/users/config.html
  options.custom.services.syncthing = {
    enable = mkOption {default = false;};
    configDir = mkOption {default = "${cfg.dataDir}/.config/syncthing";};
    dataDir = mkOption {default = "/home/${cfg.user}";};
    devices = mkOption {
      default = [
        "myne"
        "mynix"
        "myork"
      ];
    };
    ignorePerms = mkOption {default = false;};
    mount = mkOption {default = null;};
    order = mkOption {default = "alphabetic";};
    type = mkOption {default = "sendreceive";};
    user = mkOption {default = config.custom.username;};
    group = mkOption {default = "users";};

    versioning = mkOption {
      default = {
        params.cleanoutDays = "7";
        type = "trashcan";
      };
    };

    # Per folder attributes override config
    folders = mkOption {
      default = let
        #?? "FOLDER" = folder "ID" [ "DEVICES" ]
        folder = id: devices: {inherit id devices;};
      in {
        "SYNC/.backup" = folder "oxdvq-dfzjk" [];
        "SYNC/.ignore" = folder "qpvfw-j127s" [
          "myeck"
          "myxel"
        ];
        "SYNC/android" = folder "y3omj-gpjch" ["myxel"];
        "SYNC/common" = folder "fcsij-g7cnw" ["myxel"];
        "SYNC/dev" = folder "fsmar-4wsd3" ["myxel"];
        "SYNC/edu" = folder "4nyqw-jfkq2" ["myxel"];
        "SYNC/game" = folder "xvdpp-mxlki" [
          "myeck"
          "zendows"
        ];
        "SYNC/linux" = folder "ieikk-bnm7u" ["myxel"];
        "SYNC/mac" = folder "yjmt6-z7u4m" [];
        "SYNC/owo" = folder "ervqc-ebnzz" ["myxel"];
        "SYNC/windows" = folder "2hmna-vfap9" [];
        "ZEL/android" =
          folder "gn2l3-2hxtu" [
            "zendows"
            "zexel"
          ]
          // {
            type = "receiveonly";
          };
        "ZEL/music" =
          folder "nytcx-uwqs7" ["zendows"]
          // {
            type = "receiveonly";
          };
      };
    };
  };

  config = mkIf cfg.enable {
    services.syncthing = {
      enable = true;
      configDir = cfg.configDir;
      dataDir = cfg.dataDir;
      extraFlags = ["-no-default-folder"]; # Disable automatic creation of Sync folder
      guiAddress = "0.0.0.0:8384"; # Open to all interfaces
      openDefaultPorts = true; # Open transfer/discovery ports
      user = cfg.user;
      group = cfg.group;

      # https://docs.syncthing.net/rest/config.html
      # Undocumented endpoints can be manually extended onto /rest/config/*
      #?? "END/POINT" = null
      #!! Untrusted devices/folders are not exposed via options
      # https://github.com/NixOS/nixpkgs/issues/121286
      #!! GUI configured imperatively
      settings = {
        options.urAccepted = -1; # Decline usage statistics

        # BUG: Defaults are not applied via API
        # https://github.com/syncthing/syncthing/issues/6748
        # https://github.com/NixOS/nixpkgs/issues/268282
        "defaults/ignores".lines = [
          # Linux
          "(?d).~*"
          "(?d).directory"
          "(?d)*.kate-swp"

          # macOS
          "(?d).DS_Store"
          "(?d).Spotlight-V100"
          "(?d).Trashes"
          "(?d)__MACOSX"

          # Windows
          "(?d)~*"
          "(?d)*.laccdb"

          # Development
          "(?d).venv"
          "(?d).data"
          "(?d)*.lock"
          "(?d)*.meldcmp"
          "(?d)node_modules"
        ];

        # Devices can be declared globally without issue
        # Syncthing seems to ignore entries that match the machine's id
        devices = {
          myne = {
            introducer = true;
            id = "3YFGJ2J-X2653BB-WHKO54B-7FSL4LH-4CP4AUX-ZSUNIXW-NOBWBAN-324UOQR";
          };

          mynix.id = "UFLECA5-QQUKD5J-FQB55TE-YKKHD37-VT5ASXU-4EGUZNV-KW7Z434-FBI7CQ2";
          myork.id = "UTVTIWY-6YCR2XG-UPCUFDX-O6AVZQP-XJM7ZA6-CPAL6LP-YS4LFUA-XMTO6QG";
          myxel.id = "JXIWWYX-7YPOZKV-HPPCPZW-25P34XV-Z7RB7NY-46QN26M-YNP3S4I-UQEISAH";
          myeck.id = "NLGUPGG-XFGRDSE-43MQEXO-TLEW2XD-DMOL6RM-RPQ4IFQ-GENDXPF-PM7NQAO";
          zendows.id = "4JS6YSF-OBZFPYW-B3OUF4G-R6DVOZ4-KFAVGFY-NT4J223-E44HK3D-GPYAFQP";
          zexel.id = "VYG4QAC-SY7ET5F-CHIPQUN-TP6P7WN-LQCT3HO-UBS73JG-ZGOKCLG-SHWZOAN";
        };

        # Simplify boilerplate folders
        folders =
          concatMapAttrs (name: folder: {
            "~/${name}" =
              {
                ignorePerms = cfg.ignorePerms;
                label = name;
                order = cfg.order;
                type = cfg.type;
                versioning = cfg.versioning;
              }
              // folder
              // {devices = cfg.devices ++ folder.devices or [];};
          })
          cfg.folders;
      };
    };

    systemd = {
      # Ensure creation of config directory
      tmpfiles.rules = ["d ${cfg.configDir} - ${cfg.user} ${cfg.group}"];

      #!! Syncthing needs to start after mounting or there is a risk of file deletion
      # https://github.com/NixOS/nixpkgs/blob/nixos-unstable/nixos/modules/services/networking/syncthing.nix#L646
      #?? systemctl status
      services.syncthing = mkIf (isString cfg.mount) {
        after = [cfg.mount];
        bindsTo = [cfg.mount]; # Start/stop service on mount/unmount
      };
    };
  };
}