{
  pkgs,
  pkgs-unstable,
  lib,
  nixvim,
  river-shifttags,
  other-transcode,
  kitty-unstable,
  nix-doom-emacs-unstraightened,
  cassowary,
  ...
}: let
  username = "khais";
in {
  imports = [
    ./stylix.nix
    ./wm
    ./direnv.nix
    nix-doom-emacs-unstraightened
  ];
  home = {
    packages = with pkgs; [
      # system tools & bragging
      htop
      fastfetch
      ripgrep
      usbutils
      wget
      curl
      dua
      du-dust
      trashy
      unzip
      parallel
      tcpdump
      libqalculate
      ouch
      inetutils
      fd
      # used for yazi epub previews
      epub-thumbnailer
      # remote working
      remmina
      # communication
      discord
      # passwords
      bitwarden-desktop
      bitwarden-cli
      # editors
      nixvim
      # make clipboard yanking work in neovim
      # https://superuser.com/a/1803183
      wl-clipboard
      # wm river utils
      playerctl
      brightnessctl
      river-shifttags
      wlr-randr
      mako
      libnotify
      # dev tools
      gitu
      lnav
      # music
      cmus
      # music collection tools
      picard
      kid3
      # audio
      audacity
      pavucontrol
      openai-whisper
      # video
      mpv
      other-transcode
      ani-cli
      # file sending
      magic-wormhole
      # drawing apps
      krita
      inkscape
      # office apps
      libreoffice-fresh
      recoll
      # spell check
      ispell
      hunspell
      (aspellWithDicts (d: [d.fr d.de d.en]))
      hunspellDicts.fr-moderne
      hunspellDicts.de-de
      hunspellDicts.en-us
      # nixos tools
      nh
      nix-output-monitor
      alejandra
      # archiving
      archivebox
      # games
      lutris
      wine
      prismlauncher
      # ai
      ollama
      # windows
      cassowary
      # xmonad
      # apparently this is needed for the haskell lsp
      ghc
      i3lock
      xmobar
      # show volume in xmobar
      alsa-utils
      # remote
      rustdesk
      # other lsps
      nixd
      nil
      # used for jujutsu watch
      watchman
    ];

    file = {
      # konsole configuration
      ".local/share/konsole/Nixos.profile".source = ./konsole/Nixos.profile;
      ".config/nixpkgs/config.nix".text = ''
        { allowUnfree = true; }
      '';
    };

    sessionVariables = {
      EDITOR = "hx";
    };

    inherit username;
    homeDirectory = "/home/${username}";

    stateVersion = "23.11";
  };

  nixpkgs.config.allowUnfree = true;

  programs.git = {
    enable = true;
    userEmail = "khais.colin@gmail.com";
    userName = "Khaïs COLIN";
    # better diffs
    diff-so-fancy.enable = true;
    # always show diff in commits
    extraConfig.commit.verbose = true;
  };

  programs.jujutsu = {
    package = pkgs-unstable.jujutsu;
    enable = true;
    ediff = true;
    settings = {
      core = {
        # monitor filesystem for changes for faster snapshots in large repos
        fsmonitor = "watchman";
        # automatically snapshot on file changes
        watchman.register-snapshot-trigger = true;
      };
      user = {
        email = "khais.colin@gmail.com";
        name = "Khaïs COLIN";
      };
      signing = {
        behavior = "own";
        backend = "ssh";
        key = "/home/khais/.ssh/id_ed25519.pub";
      };
      ui = {
        editor = "hx";
        default-command = "log";
        movement.edit = true;
        # do not page if output fits on one screen
        pager = "less -FRX";
      };
      fix.tools = {
        clang-format = {
          command = ["${pkgs.clang-tools}/bin/clang-format" "--assume-filename=$path"];
          patterns = ["glob:'**/*.cpp'" "glob:'**/*.hpp'"];
        };
        whitespace = {
          command = ["${pkgs.perl}/bin/perl" "-p" "-e" "s/ +$//" "$path"];
          patterns = ["glob:'**/*'"];
        };
      };
      templates.draft_commit_description = ''
        concat(
          description,
          surround(
            "\nJJ: This commit contains the following changes:\n", "",
            indent("JJ:     ", diff.stat(72)),
          ),
          "\nJJ: ignore-rest\n",
          diff.git(),
        )
      '';
      aliases = {
        tug = ["bookmark" "move" "--from" "heads(::@- & bookmarks())" "--to" "@-"];
      };
      git = {
        write-change-id-header = true;
      };
    };
  };

  programs.zsh = {
    enable = true;
    enableVteIntegration = true;
    prezto = {
      enable = true;
    };
    shellAliases = {
      gc = "git commit -v";
      ga = "git add";
      gst = "git status";
      gp = "git push";
      gd = "git diff";
      gds = "git diff --staged";

      vim = "hx";
      vi = "hx";

      # progress cp
      # https://serverfault.com/questions/43014/copying-a-large-directory-tree-locally-cp-or-rsync
      pcp = "rsync --info=progress2 --archive --hard-links --acls --xattrs --human-readable --sparse --stats";
    };
    initExtra = ''
      # enable jj completion
      source <(jj util completion zsh)

      # bind ctrl-backspace to delete word
      bindkey '^H' backward-kill-word
    '';
  };

  programs.fish = {
    enable = true;
    shellAliases = {
      vim = "hx";
      vi = "hx";
      cat = "bat";
      ls = "eza";

      # progress cp
      # https://serverfault.com/questions/43014/copying-a-large-directory-tree-locally-cp-or-rsync
      pcp = "rsync --info=progress2 --archive --hard-links --acls --xattrs --human-readable --sparse --stats";
    };
  };

  programs.kitty = {
    package = kitty-unstable;
    enable = true;
    keybindings = {
      "super+shift+enter" = "new_os_window_with_cwd";
    };
    settings = {
      text_fg_override_threshold = 10;
    };
  };
  programs.fuzzel.enable = true;

  programs.zellij.enable = true;

  programs.ssh = {
    enable = true;
    matchBlocks = {
      "quasar" = {
        hostname = "109.199.126.230";
        user = "root";
      };
      "*.005540.xyz" = {
        port = 2201;
      };
      "005540.xyz" = {
        port = 2201;
      };
      "void" = {
        port = 2201;
      };
      "void.hummingbird-stork.ts.net" = {
        port = 2201;
      };
    };
  };

  # default connection to qemu for virt-manager
  dconf.settings = {
    "org/virt-manager/virt-manager/connections" = {
      autoconnect = ["qemu:///system"];
      uris = ["qemu:///system"];
    };
  };

  programs.beets = {
    enable = true;
    settings = {
      directory = "/pile/Music";
      library = "/pile/beets.db";
      import = {
        move = false;
        copy = true;
        incremental = false;
        write = true;
      };
      plugins = ["lyrics" "web" "info" "edit"];
    };
  };

  programs.yt-dlp = {
    enable = true;
    settings = {
      embed-thumbnail = true;
      embed-subs = true;
      sub-langs = "all";
    };
  };

  programs.doom-emacs = {
    enable = true;
    doomDir = ./doom.d;
    extraBinPackages = with pkgs; [clang-tools nil nixd haskell-language-server ghc];
  };

  programs.yazi = {
    enable = true;
    enableFishIntegration = true;
    plugins = {
      epub-preview =
        pkgs.fetchFromGitHub
        {
          owner = "kirasok";
          repo = "epub-preview.yazi";
          rev = "2e8079e4a7f6315de99a5b968ed5fda479f1f39c";
          hash = "sha256-wHTR8frrFL3cUD8fvSTO+m/77wQ7auVjTZ1uCTB/UzU=";
        };
      quick-folder = ./quick-folder.yazi;
    };
    settings = {
      plugin.prepend_previewers = [
        {
          mime = "application/epub+zip";
          run = "epub-preview";
        }
      ];
      # larger rename box
      input.rename_offset = [0 1 200 3];
    };
    keymap = {
      mgr.prepend_keymap = [
        {
          on = ["g" "j"];
          run = "cd ~/Johnny.Decimal";
          desc = "Go to Johnny Decimal";
        }
        {
          on = "A";
          run = "create --dir";
          desc = "Create directory";
        }
        {
          on = "b";
          run = ["plugin quick-folder"];
          desc = "Create directory with name of hovered file and move selected files into it";
        }
      ];
    };
  };

  xsession.windowManager.xmonad = {
    enable = true;
    config = ./xmonad.hs;
    enableContribAndExtras = true;
  };

  programs.xmobar = {
    enable = true;
    extraConfig = builtins.readFile ./xmobarrc;
  };

  programs.rofi.enable = true;

  # email
  programs.mbsync.enable = true;
  programs.msmtp.enable = true;
  programs.offlineimap.enable = true;

  programs.lieer = {
    enable = true;
  };

  accounts.email.accounts.gmail = {
    address = "khais.colin@gmail.com";
    lieer = {
      enable = true;
      settings.local_trash_tag = "killed";
      sync.enable = true;
    };
    msmtp.enable = true;
    notmuch.enable = true;
    primary = true;
    realName = "Khaïs COLIN";
    signature = {
      text = ''
        Cordialement,
        -- Khaïs COLIN
      '';
      showSignature = "append";
    };
    passwordCommand = "cat /home/khais/.home-manager-gmail-password";
    userName = "khais.colin@gmail.com";
    flavor = "gmail.com";
  };

  accounts.email.accounts.orange = {
    address = "kh.col@orange.fr";
    offlineimap = {
      enable = true;
    };
    msmtp.enable = true;
    notmuch.enable = true;
    realName = "Khaïs COLIN";
    signature = {
      text = ''
        Cordialement,
        -- Khaïs COLIN
      '';
      showSignature = "append";
    };
    passwordCommand = "cat /home/khais/.home-manager-orange-password";
    userName = "kh.col@orange.fr";
    imap = {
      host = "imap.orange.fr";
      port = 993;
    };
    smtp = {
      host = "smtp.orange.fr";
    };
  };

  programs.notmuch = {
    enable = true;
    new = {
      tags = ["new" "unread"];
    };
    hooks = {
      preNew = "gmi sync --path ~/Maildir/gmail; offlineimap";
      postNew = "afew --verbose --tag --new";
    };
    search.excludeTags = [
      "killed"
      "spam"
    ];
  };

  programs.afew = {
    enable = true;
    extraConfig = builtins.readFile ./afew.config;
  };

  programs.helix = {
    enable = true;
    ignores = [".jj/"];
    settings = {
      theme = lib.mkForce "modus_vivendi";
      editor = {
        cursor-shape = {
          insert = "bar";
          normal = "block";
          select = "underline";
        };
        end-of-line-diagnostics = "hint";
      };
    };
  };

  programs.bat = {
    enable = true;
  };

  programs.eza = {
    enable = true;
    git = true;
    icons = true;
  };

  programs.starship = {
    enable = true;
    settings = {
      # short prompt timeout
      command_timeout = 30;
      # custom.jj = {
      #   command = ''
      #     jj log -r@ -n1 --ignore-working-copy --no-graph --color always -T '
      #       separate(" ",
      #         bookmarks.map(|x| truncate_end(10, x.name(), "…")).join(" "),
      #         tags.map(|x| truncate_end(10, x.name(), "…")).join(" "),
      #         surround("\"", "\"", truncate_end(24, description.first_line(), "…")),
      #         if(conflict, "conflict"),
      #         if(divergent, "divergent"),
      #         if(hidden, "hidden"),          )
      #     '
      #   '';
      #   when = "jj root --ignore-working-copy";
      #   symbol = "jj";
      # };
      # custom.jjstate = {
      #   command = ''
      #     jj log -r@ -n1 --ignore-working-copy --no-graph --stat | tail -n1 | ${pkgs.sd}/bin/sd "(\d+) files? changed, (\d+) insertions?\(\+\), (\d+) deletions?\(-\)" ' ''${1}m ''${2}+ ''${3}-' | ${pkgs.sd}/bin/sd " 0." ""
      #   '';
      #   when = "jj root";
      # };
      git_state.disabled = true;
      git_commit.disabled = true;
      git_metrics.disabled = true;
      git_branch.disabled = true;
    };
  };
}
