inputs@{ machine, ... }:
{
  imports = machine.program {
    name = "fish";
    inherit inputs;
    requirements = [ "cli" ];
    home-config =
      {
        config,
        pkgs,
        lib,
        ...
      }:
      with builtins;
      with lib.attrsets;
      let
        scripts = (import ./scripts.nix) pkgs;
        aliases = with scripts; {
          "cp-mov" = cp-media "mov" "movies";
          "cp-ser" = cp-media "ser" "shows";
          "cp-ani" = cp-media "ani" "anime";
          "dumpasm" = "${pkgs.custom.dumpasm}/bin/dumpasm";
          "p" = builtins.trace calc calc;
          "s" = "systemctl";
          "j" = "journalctl";
          "ju" = "journalctl -u";
          "jfu" = "journalctl -fu";
          "ls" = "${pkgs.eza}/bin/eza --git";
          "ll" = "${pkgs.eza}/bin/eza --git";
          "lt" = "${pkgs.eza}/bin/eza --long --tree -L 3";
          "open" = "${pkgs.xdg-utils}/bin/xdg-open";
          "cb" = "${pkgs.wl-clipboard-rs}/bin/wl-copy";
          "cat" = "${pkgs.bat}/bin/bat";

          # "pull" = "${pkgs.git}/bin/git pull";
          # "push" = "${pkgs.git}/bin/git push";
          # "commit" = "${pkgs.git}/bin/git commit";
          # "add" = "${pkgs.git}/bin/git add";
          # "patch" = "${pkgs.git}/bin/git add -p";
          # "amend" = "${pkgs.git}/bin/git commit --amend";
          # "log" = "${pkgs.git}/bin/git log --all --graph --decorate";
          # "st" = "${pkgs.git}/bin/git status";
          # "checkout" = "${pkgs.git}/bin/git checkout";
          # "rebase" = "${pkgs.git}/bin/git rebase";
          # "stash" = "${pkgs.git}/bin/git stash";

          "edit" = "jj edit";
          "old" = "jj edit @-";
          "new" = "jj edit @+";
          "rebase" = "jj rebase";
          "pull" = "jj git fetch; jj catchup";
          "msg" = "jj describe -m";
          "branch" = "jj bookmark set";
          "stat" = "jj status";
          "push" = "jj git push";

          "tidy" = "x test tidy --bless";
          "ui" = "x test tests/ui/";

          "f" = "nautilus --no-desktop . &";
        };
        # extracting any compressed format
        extract = ''
          function extract -a file -d "decompress a file"
            if not test -f $file
              echo "'$file' is not a valid file"
              return 1
            end
            switch $file
              # tar can automatically figure out how to decompress
              case '*.{tar,tar.{bz2,zst,gz,xz},tbz2,tgz'; ${pkgs.gnutar}/bin/tar xf $file; end
              case '*.bz2'; bunzip2 $file; end
              case '*.rar'; unrar e $file; end
              case '*.gz'; gunzip $file; end
              case '*.zip'; ${pkgs.unzip}/bin/unzip $file; end
              case '*.Z'; uncompress $file; end
              case '*.7z'; 7z x $file; end
              case '*';
                echo "'$file' cannot be extracted"
                return 1
            end
          end
        '';
      in
      {
        programs = {
          atuin = {
            enable = true;
            enableFishIntegration = true;

            settings = {
              filter_mode_shell_up_key_binding = "workspace";
              exit_mode = "return-original";
              inline_height = 20;
              workspaces = true;
            };
          };

          zoxide = {
            enable = true;
            enableFishIntegration = true;
          };

          direnv = {
            enable = true;
            # enableFishIntegration = lib.mkDefault true;
          };

          fzf = {
            enable = true;
            enableFishIntegration = true;
          };

          fish = {
            enable = true;
            shellAliases = aliases;
            plugins = with pkgs.fishPlugins; [
              {
                name = "bang-bang";
                src = pkgs.fetchFromGitHub {
                  owner = "oh-my-fish";
                  repo = "plugin-bang-bang";
                  rev = "ec991b80ba7d4dda7a962167b036efc5c2d79419";
                  hash = "sha256-oPPCtFN2DPuM//c48SXb4TrFRjJtccg0YPXcAo0Lxq0=";
                };
              }
              {
                name = "tide";
                inherit (tide) src;
              }
              {
                name = "sponge";
                inherit (sponge) src;
              }
              {
                name = "autopair";
                inherit (autopair) src;
              }
            ];

            functions = {
              fish_jj_prompt = {
                body = ''
                  if not ${config.programs.jujutsu.package}/bin/jj root --quiet &>/dev/null
                    return 1
                  end

                  ${config.programs.jujutsu.package}/bin/jj log --ignore-working-copy --no-graph --color always -r @ -T '
                    separate(
                      " ",
                      bookmarks.join(", "),
                      change_id.shortest(),
                      commit_id.shortest(),
                      if(conflict, "conflict"),
                      if(empty, "empty"),
                      if(divergent, "divergent"),
                      if(hidden, "hidden"),
                    )
                  '
                '';
              };

              _tide_item_jj = {
                body = ''
                  set -l _tide_item_jj_color $_tide_location_color
                  echo -ns $_tide_item_jj_color" ("(fish_jj_prompt)$_tide_item_jj_color")"
                '';
              };

              _tide_item_git = {
                body = ''
                  if not test -d .jj
                    fish_git_prompt '%s'
                  end
                '';
              };
            };

            interactiveShellInit = ''
              fish_vi_key_bindings

              bind \e\[3\;5~ kill-word
              bind \cH backward-kill-word
              bind \cV beginning-of-line
              bind \f end-of-line

              bind -M insert \e\[3\;5~ kill-word
              bind -M insert \cH backward-kill-word
              bind -M insert \cV beginning-of-line
              bind -M insert \f end-of-line

              bind \cl 'clear; commandline -f repaint'
              bind -M insert \cl 'clear; commandline -f repaint'

              set -g sponge_successful_exit_codes 0
              set -g sponge_allow_previously_successful false
              set -g sponge_delay 10

              ${config.programs.jujutsu.package}/bin/jj util completion fish | source

              # if set -q tide_left_prompt_items; and not contains "jj" $tide_left_prompt_items
              #   set -l tide_item_jj_idx (contains -i "pwd" $tide_left_prompt_items)
              #   if test $tide_item_jj_idx
              #     set tide_left_prompt_items \
              #       $tide_left_prompt_items[1..$tide_item_jj_idx] \
              #       jj \
              #       $tide_left_prompt_items[(math $tide_item_jj_idx + 1)..-1]
              #   end
              # end

              function t
                  cd "$(${pkgs.custom.t}/bin/t-rs $argv | tail -n 1)"
              end

              function temp
                  t $argv
              end

              function rs
                  cd "$(${pkgs.custom.t}/bin/t-rs $argv | tail -n 1)"
                  cargo init . --bin --name $(basename "$PWD")
                  vim src/main.rs
              end

              fish_add_path "$HOME/.cargo/bin"
              fish_add_path "$HOME/.local/bin"
              fish_add_path "$HOME/Documents/scripts"
              fish_add_path "$HOME/.nix-profile/bin"

              function fish_greeting
                ${pkgs.blahaj}/bin/blahaj -s
                echo "welcome to $(uname -n), $(whoami)!"
              end
            '';
          };
        };

        home.activation = {
          setupTide = lib.hm.dag.entryAfter [ "writeBoundary" ] ''
            setupTide() {
              ${pkgs.fish}/bin/fish -c ${lib.escapeShellArg "tide configure ${
                lib.cli.toGNUCommandLineShell { } {
                  auto = true;
                  style = "Lean";
                  prompt_colors = "True color";
                  show_time = "No";
                  lean_prompt_height = "Two lines";
                  prompt_connection = "Disconnected";
                  prompt_spacing = "Compact";
                  icons = "Few icons";
                  transient = "Yes";
                }
              }"} >/dev/null 2>&1
            }
            setupTide
          '';
        };
      };
  };
}
