{ config, lib, pkgs, inputs, ... }@args:

let cfg = config.sydnix.emacs;
in {
  options.sydnix.emacs = {
    enable = lib.mkEnableOption "Emacs";
    defaultEditor = lib.mkOption {
      description = ''
        Set as default editor?
      '';
      default = false;
      type = lib.types.bool;
    };
    userDir = lib.mkOption {
      description = ''
        The path to the Emacs user directory.
      '';
      # Mutable config.
      default = "/persist/dots/modules/home/users/msyds/emacs";
      type = lib.types.path;
    };
    package = lib.mkPackageOption pkgs "emacs" {
      default = [ "emacs-pgtk" ];
    };
    emacsPackages = lib.mkOption {
      description = ''
        Emacs packages to be installed.  Used primarily for Elisp packages with
        system dependencies.
      '';
      default = _epkgs: [];
      type = lib.types.anything // {
        merge =
          _loc: defs: epkgs: lib.concatMap (f: f epkgs) (lib.getValues defs);
        check = lib.isFunction;
      };
    };
    fontPackages = lib.mkOption {
      description = ''
        Font packages to be made available to Emacs.
      '';
      type = lib.types.listOf lib.types.package;
      default = [];
    };
    tex = {
      enable = lib.mkEnableOption "TexLive";
      extraTexPackages = lib.mkOption {
        description = ''
          TexLive package to be made available.
        '';
        default = {};
        type = lib.types.attrsOf lib.types.anything;
      };
    };
    extraWrapProgramArgs = lib.mkOption {
      description = ''
        Extra arguments to pass to the final wrapProgram call.
      '';
      default = [];
      type = lib.types.listOf lib.types.str;
      apply = lib.escapeShellArgs;
    };
  };

  config = lib.mkIf cfg.enable
    (let
      emacsDataDir = "${config.xdg.dataHome}/emacs";
      emacsCacheDir = "${config.xdg.cacheHome}/emacs";

      warnings =
        if config.fonts.fontconfig.enable
        then []
        else [''This Emacs config will have font issues if
                fonts.fontconfig.enable is not enabled.''];

      essentialTexPackages = {
        inherit (pkgs.texlive)
          scheme-basic # Set of common packages.
          fontspec
          dvisvgm dvipng wrapfig # For Org-mode previews/export.
          amsmath # Essential for mathematics.
          spath3 # TikZ dependency?
          ulem hyperref
          capt-of
          pgf # Includes TikZ.
          tikz-cd # Commutative diagrams w/ TikZ.
          quiver # Commutative diagrams w/ TikZ & q.uiver.app.
          metafont
          preview # For new-gen org-latex-preview.
          mylatexformat # For new-gen org-latex-preview.
          collection-fontsrecommended # Essential fonts.
          etoolbox # For Org-mode exports.
          ;
      };

      my-texlive = pkgs.texlive.combine
        (essentialTexPackages // cfg.tex.extraTexPackages);

      sydmacs =
        let ewp = (pkgs.emacsPackagesFor cfg.package).emacsWithPackages
                    cfg.emacsPackages;
        in pkgs.symlinkJoin {
          name = "sydmacs";
          paths = [ ewp ];
          nativeBuildInputs = [
            pkgs.makeWrapper
          ];
          postBuild =
            let
              runtime-binaries = [
                pkgs.git # Dependency of Straight.el.
                pkgs.ghostscript # For TeX.
                my-texlive
                pkgs.unzip # For jump-to-source.
              ];
            in ''
              # Read all emacs binaries into a Bash array.
              readarray -d "" emacsen \
               < <(find "$out/bin" \( -name emacs -or -name 'emacs-*' \) -print0)

              for emacs in "''${emacsen[@]}"; do
                wrapProgram "$emacs" \
                  --add-flags "--init-directory \"${cfg.userDir}\"" \
                  --prefix PATH : "${lib.makeBinPath runtime-binaries}" \
                  ${cfg.extraWrapProgramArgs}
              done
            '';
          meta = cfg.package.meta;
          version = cfg.package.version;
        };
    in {
      
      # Set emacsclient as the default editor for the time being.
      home.sessionVariables = {
        EDITOR = "emacsclient";
        VISUAL = "emacsclient";
      };

      programs.emacs = {
        enable = true;
        package = sydmacs;
      };

      sydnix.impermanence.cache.directories = [
        # Impermanence expects the path to be relative to ~.
        (lib.removePrefix "${config.home.homeDirectory}/" emacsCacheDir)
      ];

      sydnix.impermanence.directories = [
        # Impermanence expects the path to be relative to ~.
        (lib.removePrefix "${config.home.homeDirectory}/" emacsDataDir)
      ];

      home.packages = cfg.fontPackages;

      services.emacs = {
        enable = true;
        # Generate a desktop entry for emacsclient.
        client.enable = true;
      };

      # We do this ourselves.
      stylix.targets.emacs.enable = false;
    });
}
