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

with lib;
let
  f = pkgs.writeFishApplication {
    name = "f";
    runtimeInputs = with pkgs; [ fzf bat ];
    text = /* fish */ ''
      fzf --query "$argv" \
          --multi \
          --bind "enter:become($EDITOR {+})" \
          --preview "bat --color=always --style=header,grid --line-range :500 {+}"
    '';
  };

  which-nix = pkgs.writeFishApplication {
    name = "which-nix";
    runtimeInputs = with pkgs; [ which coreutils-full procps ];
    text = /* fish */ ''
      function recurse -a path;
        if not test -f "$path"
          return
        end

        echo $path
        if test -L $path
          recurse (readlink $path)
        end
      end

      for arg in $argv
        recurse (which $arg)
      end
    '';
    completions = /* fish */ ''
      complete -c which-nix -fa '(__fish_complete_command)'
    '';
  };

  gi = pkgs.writeFishApplication {
    name = "gi";
    runtimeInputs = with pkgs; [ fzf gum curl coreutils-full ];
    text = /* fish */ ''
      set url https://www.gitignore.io/api

      if test (count $argv) -eq 0
        set choice ( curl -sL $url/list \
                   | string split "," \
                   | fzf -m \
                   | string join "," )
      else
        set choice (string join "," $argv[1..])
      end

      set contents "$(curl -sL $url/$choice | head -n -2 | tail -n +4)"

      if gum confirm "Overwrite current .gitignore?"
        echo "$contents" > .gitignore
      else
        echo "$contents" >> .gitignore
      end
    '';
    completions = /* fish */ ''
      set args (curl -sL https://www.gitignore.io/api/list | string split ",")
      complete -c gi -fa "$args"
    '';
  };
in
{
  users.users.root.openssh.authorizedKeys.keys = [
    "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGoAqa2m7hIzZ2LS96Z+RCIlRvhBM/j7h27tMBCwMT+a" # Moritz
  ];
  users.users.moritz = {
    isNormalUser = true;
    home = "/home/moritz";
    extraGroups = [ "wheel" "networkmanager" "video" ];
    # initialPassword = "password"; # CHANGE ME PLEASE
    openssh.authorizedKeys.keys = [
      "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGoAqa2m7hIzZ2LS96Z+RCIlRvhBM/j7h27tMBCwMT+a" # Moritz
      "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDhtwHDGAZshiQWKkCcPWV9tC83b+bKBgjDcjP/N2CKO" # Laptop
      "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKl8gMhwSf1NsP5gp14xbbyjqQLZzcHLb/XKRMoHdXgI" # Desktop
      "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDHlemuKagHwz2T5rEwgJNlVUdUdOXyPtCEzD73CrwY2zmpR4AMj7y9u3Rm7HwHUDjLap1ZFwg+53bAsVP6HFZccCXoIfO/8BL0WDGQJrfgb+A+UiRhSqSvyZ77bGJkadbBkadguz3qR3PHcb41DOlhuqVcHxsY8ceHMxAuyb0pLJVJLeytMD+CHS/r7hoj2hckTNAZ+VhCXBtdZfZ7uPUBxLfluYRNNMmdwCglsg3RUS242nJUzy3A84+CXIGeWmNG9Fu45IDkwMthxSW9klyU9R38R9DBDcugkyb6vz+JKSuRVAa47qh/kmtsYekfL3ul9D2JN32P8S+6ZoXx+gXupGJ0ltwJWAFkhLJ+yeXj9kCOv/mIUmCB14jMGsvKiSwV25O/twyjqe2LEkMVgimgrjEYoHu+ZTyp0iFtUvSrFo4tsAhfWPV9yj4F/hUksW7xKIwq5Niyx7he5M/XddudtnAximyiBDGCdJm1Ejl0UaGa6ZQv7y6VZdx0PyZuraT7l9ub8so6JlE4cVgSSU9vE0IS2QqBuHhsIjh8RVksoTR2NQbeDdGaGpGnq2C8y0rDXwE/EJA4LK45khX/GPn73n8F0kBG8dBrWgRDAEODpmebScO7d5mCeM0z3lPcRmh+3e3DPnVVOl+uR7udlc7NauLzl7q913UtxZaF1PlD7Q==" # GPG
    ];
  };

  time.timeZone = "Europe/Berlin";

  my = {
    nixpkgs = {
      overlays = [
        (_: prev:
          {
            nur = import inputs.nur {
              pkgs = prev;
              nurpkgs = prev;
            };
          }
        )
        (
          final: _:

            with final.lib;
            rec {
              fishFile =
                { name
                , destination
                , content
                , checkPhase ? null
                }:
                final.writeTextFile {
                  inherit name destination;
                  executable = true;
                  allowSubstitutes = true;
                  preferLocalBuild = false;
                  text = ''
                    #!${getExe final.fish}

                    ${content}
                  '';

                  checkPhase =
                    if checkPhase == null then ''
                      runHook preCheck
                      ${getExe final.fish} -n "$target"
                      runHook postCheck
                    ''
                    else checkPhase;
                };

              writeFishApplication =
                { name
                , text
                , completions ? null
                , runtimeInputs ? [ ]
                , checkPhase ? null
                }:
                let
                  runtimeHeader = optionalString (runtimeInputs != [ ])
                    ''export PATH="${makeBinPath runtimeInputs}:$PATH"'';

                  script = fishFile {
                    inherit checkPhase;
                    name = "${name}_script";
                    destination = "/bin/${name}";
                    content = concatLines [ runtimeHeader text ];
                  };
                  completions_file = fishFile {
                    inherit checkPhase;
                    name = "${name}_completions";
                    destination = "/share/fish/vendor_completions.d/${name}.fish";
                    content = concatLines [ runtimeHeader completions ];
                  };
                in
                final.symlinkJoin {
                  inherit name;
                  paths = [
                    script
                  ] ++ optional (completions != null) completions_file;
                };
            }
        )
        (
          _: prev: {
            xorg = prev.xorg // {
              lndir = prev.xorg.lndir.overrideAttrs (_: {
                meta.mainProgram = "lndir";
              });
            };
          }
        )
      ];
      channels = {
        master = inputs.master;
        stable = inputs.stable;
      };
    };

    bin.enable = true;
    shell = {
      abbreviations = {
        us = "systemctl --user";
        rs = "sudo systemctl";
        uj = "journalctl --user";
        rj = "sudo journalctl";
      };
      aliases = {
        ls = "${getExe pkgs.eza} -lh --icons --git";
        cat = "bat";
        rm = "rm -i";
        mv = "mv -i";

        nixos-update = "pushd ~/.dotfiles && nix flake update && popd";
      };
      variables = { EDITOR = "vim"; };
    };
    programs = {
      direnv.enable = true;
      fish.enable = true;
      git.enable = true;
      gpg.enable = true;
      nix = {
        gc.enable = true;
        optimise.enable = true;
      };
      tmux.enable = true;
      tmux.keybinds = {
        prefix = {
          "-" = "split-window -v";
          "|" = "split-window -h";
          "C-l" = "send-keys C-l";
          "R" = "source-file $XDG_CONFIG_HOME/tmux/tmux.conf \\; display-message 'Reloaded tmux.conf'";
          "f" = "new-window ts";
          "a" = "new-window ta";
        };
        copy-mode-vi = {
          "v" = "send -X begin-selection";
          "V" = "send -X select-line";
          "C-v" = "send -X rectangle-toggle";
        };
      };
    };
  };

  console.keyMap = "de";

  environment.systemPackages = with pkgs; [
    # archives
    ouch

    # monitoring
    bottom

    # nix
    nix-output-monitor
    nixpkgs-fmt
    which-nix

    # utils
    bat
    cht-sh
    f
    fd
    gi
    parallel
    ripgrep
    vim
    (viu.override { withSixel = true; })
    wget
  ];

  fonts = {
    enableDefaultPackages = true;
    packages = [
      (pkgs.nerdfonts.override {
        fonts = [ "FiraCode" ];
      })
      pkgs.master.intel-one-mono
    ];
  };

  programs = {
    mtr.enable = true;
    command-not-found.enable = false;
  };

  services = {
    sshd.enable = true; # for agenix
    btrfs.autoScrub.enable =
      lib.mkDefault
        (builtins.any (filesystem: filesystem.fsType == "btrfs")
          (builtins.attrValues config.fileSystems));
  };

  i18n.extraLocaleSettings = {
    # LC_NUMERIC = "de_DE.UTF-8";
    LC_PAPER = "de_DE.UTF-8";
    LC_TIME = "de_DE.UTF-8";
  };

  home-manager.users.moritz = {
    programs = {
      # Let Home Manager install and manage itself.
      home-manager.enable = true;
      fzf = {
        enable = true;
        defaultOptions = [
          "--height 50%"
          "--bind alt-j:preview-down,alt-k:preview-up"
        ];
      };
      zoxide = {
        enable = true;
        options = [
          "--cmd c"
        ];
      };
      starship.enable = true;
    };
    home = {
      username = "moritz";
      homeDirectory = "/home/moritz";
      stateVersion = "21.05";
    };
    xdg.userDirs.enable = true;
  };

  system.activationScripts.diff = ''
    if [ -e /run/current-system ]; then
      ${pkgs.nvd}/bin/nvd --nix-bin-dir ${pkgs.nix}/bin diff /run/current-system/ "$systemConfig"
    fi
  '';
}
