{ flake, flakeInputs, userName, pkgs, customUtils, lib, config, sources, ... }@inputs:
let
  cfg = config.home-manager.users.${userName};
  xmonad = import ./xmonad pkgs.haskell.packages.ghc8107;
  emacsScratch = pkgs.stdenv.mkDerivation (sources.emacs-scratch_el // rec {
    phases = [ "installPhase" ];

    installPhase = ''
      mkdir -p $out/share/emacs/site-lisp
      cp $src/scratch.el $out/share/emacs/site-lisp/default.el
    '';
  });
  muteScript = pkgs.stdenv.mkDerivation {
    name = "mute";
    src = ./scripts/mute.zsh;

    buildInputs = with pkgs; [ makeWrapper ];

    phases = [ "installPhase" ];

    installPhase = ''
      mkdir -p $out/bin
      install -m 0755 $src $out/bin/mute
      wrapProgram $out/bin/mute \
        --prefix PATH : ${pkgs.zsh}/bin \
        --prefix PATH : ${pkgs.findutils}/bin \
        --prefix PATH : ${pkgs.util-linux}/bin \
        --prefix PATH : ${pkgs.coreutils}/bin \
        --prefix PATH : ${pkgs.pulseaudio}/bin
    '';
  };
  wrapElectron = { package, bin ? package.meta.mainProgram or package.pname or (pkgs.lib.strings.nameFromURL package.name "-"), outBin ? bin }: pkgs.runCommand "${package.name}-wrapped" { buildInputs = with pkgs; [ makeWrapper ]; } ''
    mkdir -p "$out/bin"
    makeWrapper ${package}/bin/${bin} $out/bin/${outBin} \
      --add-flags '--force-device-scale-factor=1.6'
  '';
  
  wrappedChrome = wrapElectron { package = pkgs.google-chrome; outBin = "google-chrome"; };
  wrappedZulip = wrapElectron { package = pkgs.zulip; bin = "zulip"; outBin = "zulip"; };
  wrappedElementDesktop = wrapElectron { package = pkgs.element-desktop; bin = "element-desktop"; outBin = "element"; };
  wrappedRocketChatDesktop = wrapElectron { package = pkgs.rocketchat-desktop; bin = "rocketchat-desktop"; outBin = "rocketchat"; };
in {
  imports = with flake.nixosModules.userProfiles.${userName}; [
    mpv yt-dlp (args: import ./xcompose.nix (inputs // args))
  ];
  
  config.home-manager.users.${userName} = {
    nixpkgs.config = {
      allowUnfree = true;
      zathura.useMupdf = false;
    };
    
    programs = {
      ssh = {
        matchBlocks = import ./ssh-hosts.nix { inherit pkgs; }; # customUtils.nixImport { dir = ./ssh-hosts; };
        extraConfig = ''
          Match host uniworx3.ifi.lmu.de,uniworx4.ifi.lmu.de,uniworx5.ifi.lmu.de,uni2workgw.ifi.lmu.de,blackbeard.tcs.ifi.lmu.de,gitlab2.rz.ifi.lmu.de,oregon.tcs.ifi.lmu.de !exec "nc -z -w 1 %h %p &>/dev/null"
            ProxyJump remote.cip.ifi.lmu.de

          Match host *.mathinst.loc,*.cipmath.loc,*.math.lmu.de
            IdentityFile ~/.ssh/gkleen@mathinst.loc
            HostKeyAlgorithms +ssh-rsa
            PubkeyAcceptedAlgorithms +ssh-rsa
            ConnectTimeout 30

          Match host *.mathinst.loc !host mathw0g.mathinst.loc !exec "nc -z -w 1 %h %p &>/dev/null"
            # ProxyCommand ${pkgs.socat}/bin/socat - SOCKS4A:127.0.0.1:%h:%p,socksport=8118
            ProxyJump mathw0g

          Match host mathw0g.mathinst.loc !exec "nc -z -w 1 %h %p &>/dev/null"
            HostName mathw0g.math.lmu.de

          Match host *.cipmath.loc !exec "nc -z -w 1 %h %p &>/dev/null"
            ProxyJump mathw0h

          Match host *.ifi.lmu.de,*.math.lmu.de
            AddressFamily inet

          Match host *.mgmt.yggdrasil
            ProxyJump vidhar

          Host *
        '';
      };

      emacs = {
        enable = true;
        extraPackages = epkgs: with epkgs; [
          evil evil-dvorak undo-tree magit haskell-mode
          nix-mode yaml-mode json-mode shakespeare-mode
          smart-mode-line highlight-parentheses highlight-symbol
          ag sass-mode lua-mode fira-code-mode use-package # notmuch
          use-package-ensure-system-package git-gutter emacsScratch
          edit-server mediawiki
        ];
      };
      firefox = {
        enable = true;
        profiles.default = {
          settings = {
            "layout.css.devPixelsPerPx" = "1.75";
            "browser.tabs.drawInTitlebar" = false;
            "toolkit.legacyUserProfileCustomizations.stylesheets" = true;
            "dom.security.https_only_mode" = true;
          };
        };
      };

      alacritty = {
        enable = true;
        settings = import ./alacritty.nix;
      };

      zathura.enable = true;

      mpv.config = {
        demuxer-max-bytes = 1073741824;
        demuxer-max-back-bytes = 268435456;
        # gpu-api = "vulkan";
      };

      autorandr = {
        enable = true;
        hooks.postswitch = {
          # "restart-compton" = "${pkgs.systemd}/bin/systemctl --user try-restart picom";
          "restart-trays" = ''
              ${pkgs.coreutils}/bin/sleep 5
              ${pkgs.systemd}/bin/systemctl --user try-restart taffybar
            '';
        };
        profiles = customUtils.nixImport { dir = ./autorandr-profiles; };
      };

      zsh.initExtra = "source ${./zshrc}";
      zsh.dirHashes = let
        flakeHashes = lib.mapAttrs' (n: v: lib.nameValuePair (inputNames.${n} or n) (toString v)) flakeInputs;
        inputNames = {
          "nixpkgs" = "nixos";
        };
      in flakeHashes // {
        u2w = "$HOME/projects/uni2work";
        docs = "$HOME/documents";
        dl = "$HOME/Downloads";
        flk = "$HOME/config/nixos-flakes";
        rz = "$HOME/projects/rz";
      };

      obs-studio = {
        enable = true;
        plugins = with pkgs; [];
      };

      gh = {
        enable = true;
        settings = {
          editor = "${config.home-manager.users.${userName}.programs.emacs.package}/bin/emacsclient";
          gitProtocol = "ssh";
        };
      };

      nix-index.enable = true;
    };

    services = {
      dunst = {
        settings = import ./dunst-settings.nix inputs;
        iconTheme = cfg.gtk.iconTheme;
        enable = true;
      };
      emacs = {
        enable = true;
        client = {
          enable = true;
          arguments = lib.mkForce ["-a" "\"\""];
        };
      };
      gpg-agent = {
        enable = true;
        enableSshSupport = true;
        extraConfig = ''
          pinentry-program ${pkgs.pinentry-gtk2}/bin/pinentry
          grab
        '';
      };
      taffybar = {
        enable = true;
        package = import ./taffybar { haskellPackages = pkgs.haskell.packages.ghc8107; };
      };
      status-notifier-watcher.enable = true;
      xembed-sni-proxy.enable = true;
      pasystray.enable = true;
      udiskie = {
        enable = true;
        automount = false;
      };
      unclutter = {
        enable = true;
        timeout = 5;
      };
      network-manager-applet.enable = true;
      blueman-applet.enable = true;

      sxhkd = {
        enable = true;
        keybindings = {
          "button8" = "${muteScript}/bin/mute unmute";
          "@button8" = "${muteScript}/bin/mute mute";
          "button9" = "${pkgs.pulseaudio}/bin/pacmd set-sink-mute @DEFAULT_SINK@ 1";
          "@button9" = "${pkgs.pulseaudio}/bin/pacmd set-sink-mute @DEFAULT_SINK@ 0";
        };
      };

      unison = {
        enable = true;
        pairs = {
          documents = {
            roots = ["${cfg.home.homeDirectory}/documents" "ssh://unison.vidhar/documents"];
            stateDirectory = "${cfg.xdg.dataHome}/documents.unison";
            commandOptions = {
              auto = "true";
              batch = "true";
              log = "false";
              repeat = "watch";
              sshcmd = "${pkgs.openssh}/bin/ssh";
              ui = "text";
            };
          };
        };
      };

      easyeffects = {
        enable = true;
        preset = "LoudnessEqualizer";
      };

      screen-locker = {
        enable = true;
        lockCmd = toString (pkgs.writeShellScript "lock" ''
          cleanup() {
            ${cfg.services.dunst.package}/bin/dunstctl set-paused false
          }
          trap cleanup EXIT INT TERM

          ${pkgs.playerctl}/bin/playerctl -a pause
          ${cfg.services.dunst.package}/bin/dunstctl set-paused true
          ${pkgs.xsecurelock}/bin/xsecurelock
        '');
        xss-lock.extraOptions = ["--transfer-sleep-lock"];
      };
    };

    gtk = {
      enable = true;
      font = {
        package = pkgs.fira;
        name = "Fira Sans";
        size = 6;
      };
      theme = {
        package = pkgs.equilux-theme;
        name = "Equilux-compact";
      };
      iconTheme = {
        package = pkgs.paper-icon-theme;
        name = "Paper";
      };
      cursorTheme = lib.mkForce { inherit (cfg.xsession.pointerCursor) package name size; };
    };

    xsession = {
      enable = true;

      windowManager.command = "${pkgs.coreutils}/bin/env -u SHLVL -- ${xmonad}/bin/xmonad";

      initExtra = ''
        ${pkgs.xorg.xinput}/bin/xinput disable 'Synaptics TM3512-010'
        ${pkgs.xorg.xmodmap}/bin/xmodmap -e 'keysym Caps_Lock = Multi_key'
      '';

      pointerCursor = {
        package = pkgs.vanilla-dmz;
        defaultCursor = "left_ptr";
        name = "Vanilla-DMZ-AA";
        size = 32;
      };
    };

    xresources.properties = import ./xresources.nix;

    home = {
      packages = with pkgs; [
        fira fira-code powerline-fonts nerdfonts pavucontrol keepassxc
        sxiv xclip mumble pulseaudio-ctl pamixer libnotify synergy
        xorg.xbacklight screen-message
        google-play-music-desktop-player qt5ct playerctl evince
        thunderbird wrappedZulip zoom-us steam steam-run wireshark
        virt-manager rclone cached-nix-shell xournal xmonad worktime
        fira-code-symbols libreoffice xournalpp wrappedChrome
        nixos-shell virt-viewer freerdp gnome-icon-theme
        paper-icon-theme sshpassSecret weechat helvum
        wrappedElementDesktop matrix-synapse-tools.synadm
        wrappedRocketChatDesktop
        flakeInputs.deploy-rs.packages.${config.nixpkgs.system}.deploy-rs
      ];

      file = {
        ".emacs".source = ./emacs.el;
        ".backup-munin".source = ./backup-patterns;
        ".mozilla/firefox/default/chrome/userChrome.css".source = ./firefox-chrome.css;
        ".mozilla/firefox/default/chrome/userContent.css".source = ./firefox-content.css;
      };

      sessionVariables = {
        GDK_SCALE = 96.0 / 282.0;
        QT_AUTO_SCREEN_SCALE_FACTOR = 1;
        QT_QPA_PLATFORMTHEME = "qt5ct";
        LIBVIRT_DEFAULT_URI = "qemu:///system";
      };

      extraProfileCommands = ''
        export XDG_DATA_DIRS="${pkgs.gsettings-desktop-schemas}/share/gsettings-schemas/${pkgs.gsettings-desktop-schemas.name}:${pkgs.gtk3}/share/gsettings-schemas/${pkgs.gtk3.name}''${XDG_DATA_DIRS:+:''${XDG_DATA_DIRS}}"
      '';

      keyboard = {
        layout = "us";
        variant = "dvp";
        options = [ "ctl:nocaps" "compose:caps" ];
      };
    };

    xdg.configFile = {
      "dunst/dunstrc.d" = {
        source = ./dunstrc.d;
        recursive = true;
        onChange = ''
          ${pkgs.systemd}/bin/systemctl --user try-restart dunst
        '';
      };
      "wireplumber" = {
        source = ./wireplumber;
        recursive = true;
        onChange = ''
          ${pkgs.systemd}/bin/systemctl --user try-restart wireplumber
        '';
      };
    };

    fonts.fontconfig.enable = true;

    systemd.user = import ./systemd.nix inputs;
  };
}