#
# A fairly complete TeX environment but still as lightweight as possible.
# The idea is to get an environment where I can happily write most LaTeX docs
# without having to worry about installing common packages, but at the same
# time without bloating the Nix store with GBs of packages I'll never actually
# use---either as a direct or indirect LaTeX dependency. TeX docs aren't
# included either since I never actually use local docs, rather I Google for
# answers. Keep in mind if you need to add extras not included in the default
# set of packages provided here, you can still do that---see below.
#
# So what's in the box? Basically everything in the Nixpkgs `scheme-full`
# except for:
#
# - collection-context
# - collection-fontsextra
# - collection-games
# - collection-humanities
# - collection-lang* (but collection-langenglish is in)
# - collection-music
# - collection-texworks
# - collection-xetex
#
# Okay, but how much space am I saving? Well, `defaultEnv` (see below) eats
# up about 1.8G of your disk. In comparison, Nixpkgs `scheme-medium` takes
# about 1.6G whereas `scheme-full` needs a whooping 4.5G. Keep in mind these
# are quick & dirty figures I got for each derivation by running `du -hs /nix`
# on a clean-slate Nix store (i.e. what you get after installing Nix), then
# getting a Nix shell for the derivation and finally running `du` again to
# see how much bigger the Nix store grew. Surely YMMV.
#
# NOTE
# 1. XeTeX. It isn't there since these days it looks like LuaTeX (included)
# can do whatever XeTex can and even better---well, except for using fonts
# installed on your system, outside of the LaTeX environment.
# 2. Fonts. While we include all the recommended LaTeX fonts, we leave out
# the ones in the `fontsextra` collection. This saves about 2GB of space.
# If you need a font from `fontsextra`, just pass it in as an extra package
# when calling `mkEnv`---see below.
#
{ pkgs, ... }:
let
  xlib = import ../../lib pkgs.lib;
in rec {

  # The default set of packages included in our TeX environment.
  basePkgs = with pkgs; {
    inherit (texlive)
      collection-basic
      collection-bibtexextra
      collection-binextra
      collection-fontsrecommended
      collection-fontutils
      collection-formatsextra
      collection-langenglish
      collection-latex
      collection-latexextra
      collection-latexrecommended
      collection-luatex
      collection-mathscience
      collection-metapost
      collection-pictures
      collection-plaingeneric
      collection-pstricks
      collection-publishers
    ;
  };

  # Build a Tex environment containing the base packages plus any extras
  # given in the argument. E.g.
  #
  #     myLatex = mkEnv ["fira" "fontawesome"];
  #
  # This function returns a derivation for the TeX environment.
  mkEnv = extraPkgs:
  with builtins;
  let
    mkExtraPkgAttr = name: { ${name} = pkgs.texlive.${name}; };
    extraPkgSet = xlib.sets.mergeAll (map mkExtraPkgAttr extraPkgs);
    pkgsArg = {
      pkgFilter = pkg: pkg.tlType == "run" || pkg.tlType == "bin";  # (*)
    } // basePkgs // extraPkgSet;
  in
    pkgs.texlive.combine pkgsArg;
  # NOTE. Filtering out doc derivation outputs by not including "doc" type.

  # A TeX environment containing the base packages plus some hand-picked
  # fonts from collection-fontsextra. These are the fonts that I've been
  # using in my LaTeX docs that aren't included in the base TeX fonts.
  defaultEnv =
  let
    extraFonts = ["alegreya" "eulervm" "fontawesome" "iwona" "sourcecodepro"];
  in
    mkEnv extraFonts;


  # Build a Nix derivation to produce PDFs from LaTeX sources.
  # You specify a directory `srcDir` containing your LaTeX sources and a list
  # of target TeX files `targetFiles` within that directory tree from which to
  # generate PDFs. The Nix derivation runs the LaTeX engine at the root of
  # `srcDir` on each file in `targetFiles` and puts the generated PDF in the
  # Nix package output. This way target files can include any other TeX source
  # (using a relative path within `srcDir`) and LaTeX compilation will work
  # fine. The TeX environment we use to build is that generated by `mkEnv`
  # with any additional packages you specify.
  mkPdfs = {
    # The Nix derivation name. Defaults to "pdfs".
    pkgName ? "pdfs",
    # The directory containing the LaTeX sources.
    srcDir,
    # List of TeX file path-names (relative to `srcDir`) on which to run the
    # LaTeX engine. We output a PDF for each file.
    targetFiles,
    # List of extra Tex packages (names) to add to the TeX environment used
    # to build the PDFs. Defaults to none.
    extraPkgs ? [],
    # Value to set in the `SOURCE_DATE_EPOCH` environment variable when
    # building the PDFs. LaTeX looks at this variable when outputting dates,
    # e.g. the `\today` macro outputs the date set in `SOURCE_DATE_EPOCH`.
    # We default this value to the current time when you build the PDFs, i.e.
    # when Nix evaluates the returned derivation expression. You can change
    # that by explicitly setting this input parameter to a string containing
    # a Unix timestamp (with no fractional part, e.g. "1640713410") or to
    # a (coreutils) `date` command generating one, as in
    # "$(date -d '2021-12-28' +%s)".
    sourceDateEpoch ? "$(date +%s)"
  }:
  let
    tex = mkEnv extraPkgs;
    toPdf = target: ''
      latexmk -interaction=nonstopmode -pdf -lualatex '${target}'
    '';
    buildCmdLines = with builtins;
      concatStringsSep "\n" (map toPdf targetFiles);
  in pkgs.stdenvNoCC.mkDerivation rec {                         # (1)
    name = pkgName;
    src = srcDir;

    buildInputs = [ pkgs.coreutils tex ];                       # (2)
    phases = ["unpackPhase" "buildPhase" "installPhase"];

    buildPhase = ''
      export PATH="${pkgs.lib.makeBinPath buildInputs}";
      export SOURCE_DATE_EPOCH=${sourceDateEpoch}
      mkdir -p .cache/texmf-var
      export TEXMFHOME=.cache TEXMFVAR=.cache/texmf-var
      ${buildCmdLines}
    '';                                                         # (3)

    installPhase = ''
      mkdir -p $out
      cp *.pdf $out/
    '';
  };
# NOTE
# 1. LaTeX/Nix build commands. Ripped from this excellent blog post:
# - https://flyx.org/nix-flakes-latex/
# Read it to understand how this derivation works.
# 2. coreutils. (1) mentions using GNU coreutils to get around a portability
# issue w/ `mktemp` on BSD and macOS.
# 3. LuaLaTeX cache. (1) mentions you should set env vars to tell LuaLaTeX
# where to cache stuff.
# 4. LaTeX dates. As noted LaTeX looks at `SOURCE_DATE_EPOCH`, so we need
# to be able to set it otherwise whenever a document calls a macro like
# `\today` it gets the value Nix sets in `SOURCE_DATE_EPOCH` which is 1980
# both when using `stdenvNoCC.mkDerivation` and `stdenv.mkDerivation`---that
# was a bit of a surprise since I thought `stdenv.mkDerivation` would call
# - https://github.com/NixOS/nixpkgs/blob/master/pkgs/build-support/setup-hooks/set-source-date-epoch-to-latest.sh
# 5. Reproducible PDFs. (1) points out the date and doc ID in the PDF files
# will be different every time you build the Nix package. Not a biggie to
# me, but (1) explains how to get around that if you're that way inclined.
# 6. Fonts. If a font you need for your PDF isn't in the default fonts we
# use, you can always add it using the `extraPkgSet` argument. But what
# if that font isn't in the TexLive distro?! Guess what. (1) shows you
# how to add an arbitrary font to a Nix Flake for building LaTeX docs.
# I'm not doing it here, since it seems overkill at the moment.

}
