{ flake, flakeInputs, userName, pkgs, customUtils, lib, config, sources, ... }@inputs:

with lib;

let
  cfg = config.home-manager.users.${userName};
  deHaskell = flakeInputs.nixpkgs-stable.legacyPackages.x86_64-linux.haskell.packages.ghc8107;
  xmonad = import ./xmonad deHaskell;
  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, sandbox ? true }: 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' \
      ${optionalString (!sandbox) "--add-flags '--no-sandbox'"}
  '';

  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"; };
  wrappedYTMDesktop = wrapElectron { package = pkgs.ytmdesktop; sandbox = false; };
in {
  imports = with flake.nixosModules.userProfiles.${userName}; [
    mpv yt-dlp (args: import ./xcompose.nix (inputs // args))
  ];

  config = {
    services.xserver = {
      displayManager.defaultSession = "none+xmonad";

      windowManager.session = [{
        name = "xmonad";
        start = ''
          ${pkgs.systemd}/bin/systemd-cat -t xmonad -- ${pkgs.coreutils}/bin/env -u SHLVL -- ${xmonad}/bin/xmonad &
          waitPID=$!
        '';
      }];
    };

    home-manager.users.${userName} = {
      imports = [
        flakeInputs.nix-index-database.hmModules.nix-index
      ];

      home.stateVersion = "20.09";

      nixpkgs.config = {
        allowUnfree = true;
        zathura.useMupdf = false;
      };

      nix.registry = {
        "flk" = {
          from = {
            type = "indirect";
            id = "flk";
          };
          to = {
            type = "git";
            url = "file:///home/gkleen/config/nixos-flakes";
          };
        };
      };

      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
              PasswordAuthentication yes
              KbdInteractiveAuthentication yes
              UpdateHostKeys yes
              GlobalKnownHostsFile ${pkgs.writeText "ssh_known_hosts" ''
                @cert-authority *.mathinst.loc ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBUTFpVCdETCXiDSDl7YGbR1J4BLTsoBzjDtflHJGO/z ssh-pki@mgmt01
              ''}

            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 !host cip04.cipmath.loc !exec "nc -z -w 1 %h %p &>/dev/null"
              ProxyJump cip04

            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 wanderlust # notmuch
            use-package-ensure-system-package git-gutter emacsScratch
            edit-server mediawiki editorconfig typescript-mode
            markdown-mode nftables-mode
          ];
        };
        firefox = {
          enable = true;
          profiles.default = {
            settings = {
              "layout.css.devPixelsPerPx" = "0.5833";
              "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 = {
            preswitch = {
              "stop-tray" = ''
                ${pkgs.systemd}/bin/systemctl --user try-restart tray.target
              '';
            };
            postswitch = {
              # "restart-compton" = "${pkgs.systemd}/bin/systemctl --user try-restart picom";
              "restart-tray" = ''
                ${pkgs.systemd}/bin/systemctl --user try-restart tray.target
              '';
            };
          };
          profiles = customUtils.nixImport rec { dir = ./autorandr-profiles; _import = name: _base: import "${toString dir}/${name}" inputs; };
        };

        zsh.initExtra = "source ${./zshrc}";
        zsh.dirHashes = let
          flakeHashes = mapAttrs' (n: v: 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";
          };
        };
      };

      services = {
        dunst = {
          settings = import ./dunst-settings.nix inputs;
          iconTheme = cfg.gtk.iconTheme;
          enable = true;
        };
        emacs = {
          enable = true;
          client = {
            enable = true;
            arguments = mkForce ["-a" "\"\""];
          };
        };
        gpg-agent = {
          enable = true;
          enableSshSupport = true;
          extraConfig = ''
            pinentry-program ${pkgs.pinentry-gtk2}/bin/pinentry
            grab
          '';
        };
        taffybar = {
          enable = true;
          package = import ./taffybar { haskellPackages = deHaskell; };
        };
        status-notifier-watcher.enable = true;
        xembed-sni-proxy.enable = true;
        pasystray.enable = true;
        udiskie = {
          enable = true;
          automount = false;
          settings = {
            program_options = {
              file_manager = "";
            };
            notification_actions = {
              device_mounted = [];
            };
          };
        };
        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" ''
            ${pkgs.playerctl}/bin/playerctl -a status | ${pkgs.gnugrep}/bin/grep -q "Playing" && exit 0

            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"];
        };

        etesync-dav = {
          enable = true;
          serverUrl = "https://etesync.yggdrasil.li";
        };
      };

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

        x11 = {
          enable = true;
          defaultCursor = "left_ptr";
        };
        gtk.enable = true;
      };

      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";
        };
      };

      xsession = {
        enable = true;

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

        preferStatusNotifierItems = true;
      };

      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 wrappedYTMDesktop
          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 wrappedElementDesktop # helvum
          matrix-synapse-tools.synadm wrappedRocketChatDesktop
          flakeInputs.deploy-rs.packages.${config.nixpkgs.system}.deploy-rs
          sieve-connect gimp inkscape udiskie glab
        ];

        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;
          ".local/share/etesync-dav/CACHEDIR.TAG".text = ''
            Signature: 8a477f597d28d172789f06886806bc55
          '';
        };

        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}}"
        '';
      };

      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
          '';
        };
      };

      xdg.dataFile = {
        "pandoc/abbreviations" = {
          source = pkgs.runCommand "pandoc-abbreviations" {
            buildInputs = [ pkgs.pandoc pkgs.coreutils ];
          } (let
            germanAbbrevs = pkgs.fetchFromGitHub {
              owner = "jfilter";
              repo = "german-abbreviations";
              rev = "8eb9dae93b6f05d7c53374cd217ab2dc89558e0c";
              sha256 = "SaD3tSqzen6Y3SPICe6/9vhe4iMHlArZ3kFQaEk7Hps=";
            };
          in ''
            cat \
              <(pandoc --print-default-data-file=abbreviations) \
              <(grep -E '^[^ ]+\.$' ${germanAbbrevs}/german_abbreviations.txt) \
              ${pkgs.writeText "abbrevs.txt" ''
                i.A.
                d.h.
                D.h.
                gdw.
              ''} \
              | sort | uniq >$out
          '');
        };
      };

      xdg.mimeApps = {
        enable = true;
        defaultApplications = let
          filters = {
          };
          doFilter = n: v: (filters.${n} or id) (filter (d: d != "emacs.desktop") v);
        in mapAttrs doFilter (cfg.lib.xdg.mimeAssociations [
          cfg.programs.zathura.package
          pkgs.sxiv
          cfg.programs.emacs.package
          cfg.programs.firefox.package
        ]) // {
          "x-scheme-handler/mailto" = "thunderbird.desktop";
        };
      };

      fonts.fontconfig.enable = true;

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