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

with lib;
let
  cfg = config.my.programs.fish;
  shellConfig = config.my.shell;
  exportedVariables =
    let
      exportVariables =
        lib.mapAttrsToList (n: v: ''set -x ${n} "${v}"'') shellConfig.variables;
    in
    lib.concatStringsSep "\n" exportVariables;
in
{
  options.my.programs.fish.enable = mkEnableOption "fish";

  config = lib.mkIf cfg.enable {
    # set as default shell
    users.users.moritz.shell = pkgs.fish;
    environment.systemPackages = with pkgs.fishPlugins; [ fzf-fish pisces ];
    # needed for nix completions
    programs.fish.enable = true;

    home-manager.users.moritz = {
      programs = {
        fish = {
          enable = true;
          shellAbbrs = shellConfig.abbreviations;
          shellAliases = shellConfig.aliases;
          shellInit = ''
            # Vi Mode
            fish_vi_key_bindings

            # Emulates vim's cursor shape behavior
            # Set the normal and visual mode cursors to a block
            set fish_cursor_default block
            # Set the insert mode cursor to a line
            set fish_cursor_insert line
            # Set the replace mode cursor to an underscore
            set fish_cursor_replace_one underscore
            # The following variable can be used to configure cursor shape in
            # visual mode, but due to fish_cursor_default, is redundant here
            set fish_cursor_visual block

            # Complex abbreviations
            function last_history_item
              echo $history[1]
            end
            abbr -a !! --position anywhere --function last_history_item

            function sed_history_item
              echo $history[1] | perl -p -e (string trim -l --chars=! $argv)
            end
            abbr -a sed_history --position command --regex '^!s/.+/.*/g?' --function sed_history_item

            function multicd
              echo cd (string repeat -n (math (string length -- $argv[1]) - 1) ../)
            end
            abbr --add dotdot --regex '^\.\.+$' --function multicd

            abbr -a P --position anywhere --set-cursor "% | $PAGER"

            function editor_edit
              echo $EDITOR $argv
            end
            abbr -a editor_edit_files --position command --regex ".+\.(txt|md|org)" --function editor_edit

            function editor
              echo $EDITOR
            end
            abbr -a e --function editor

            # Completions
            complete -c c -kfa '(zoxide query -l | sed "s|$HOME|~|")'
            ${optionalString config.virtualisation.podman.dockerCompat /* fish */ "complete -c docker -w podman"}
            complete -c nom -fn "not __fish_seen_subcommand_from build shell develop" -a "build shell develop"

            complete -c nom -fn "__fish_seen_subcommand_from build" -w "nix build"
            complete -c nom -fn "__fish_seen_subcommand_from shell" -w "nix shell"
            complete -c nom -fn "__fish_seen_subcommand_from develop" -w "nix develop"

            complete -c timers \
              -n "__fish_seen_subcommand_from toggle" \
              -fa '(timers --json l | ${getExe pkgs.jq} -r .[][].name)'
            complete -c timers \
              -n "__fish_seen_subcommand_from remove" \
              -fa '(timers --json l | ${getExe pkgs.jq} -r .[][].name)'

            # Variables
            ${exportedVariables}
          '';
          functions = {
            fish_greeting = "";
            cheat = "cht.sh $argv | bat -p";
            sourceenv = ''
              set -f envfile "$argv"
              if not test -f "$envfile"
                echo "Unable to load $envfile"
                return 1
              end
              printf "exported"
              while read line
                if not string match -qr '^#|^$' "$line"
                  set item (string split -m 1 '=' $line)
                  printf " $item[1]"
                  set -gx "$item[1]" "$item[2]"
                end
              end < "$envfile"
              printf "\n"
            '';
          };
        };
      };
    };
  };
}
