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

  user = "mainUser";
  userName = config.users.users.mainUser.name;
  home = config.users.users.mainUser.home;
  fontSize = config.programs.custom.urxvt.fontSize;

  startupBanner = pkgs.fetchurl {
    url =
      "https://github.com/NixOS/nixos-homepage/raw/master/logo/nix-wiki.png";
    sha256 = "1hrz7wr7i0b2bips60ygacbkmdzv466lsbxi22hycg42kv4m0173";
  };

  ticks = "\"''\"";

in
{

  environment.systemPackages = [
    # needed for the SPC p g
    pkgs.universal-ctags
    pkgs.nodePackages.tern
    pkgs.emacs
  ];

  # download git repositories into the home folder
  systemd.services =
    let
      clone = repository: folder: branch: {
        enable = true;
        wantedBy = [ "multi-user.target" ];
        description = "clone ${repository} to ${folder}";
        serviceConfig.User = userName;
        unitConfig.ConditionPathExists = "!${folder}";
        script = ''
          ${pkgs.git}/bin/git clone ${repository} --branch ${branch} ${folder}
        '';
      };
    in
    {
      spacemacs-pull =
        clone "https://github.com/syl20bnr/spacemacs" "${home}/.emacs.d" "master";
      # todo move this to spacevim.nix
      spacevim-pull =
        clone "https://github.com/SpaceVim/SpaceVim.git" "${home}/.SpaceVim"
          "master";
    };

  home-manager.users."${user}" = {

    # a file which needs to be included at the end
    home.file.".spacemacs.d/hook-init.el".text = ''
      ;; -*- mode: emacs-lisp -*-
      ;; just add (load "~/.spacemacs.d/hook-init.el") in your dotspacemacs/init function

      ;; overrides of dotspacemacs/init ()
      (setq

       ;; List of themes, the first of the list is loaded when spacemacs starts.
       ;; Press <SPC> T n to cycle to the next theme in the list (works great
       ;; with 2 themes variants, one dark and one lixft:inconsolata:pixelsizeght)
       dotspacemacs-themes '(solarized-light solarized-dark)

       ;; Specify the startup banner. Default value is `official', it displays
       ;; the official spacemacs logo. An integer value is the index of text
       ;; banner, `random' chooses a random text banner in `core/banners'
       ;; directory. A string value must be a path to an image format supported
       ;; by your Emacs build.
       ;; If the value is nil then no banner is displayed. (default 'official)
       dotspacemacs-startup-banner "${startupBanner}"

       ;; Default font, or prioritized list of fonts. `powerline-scale' allows to
       ;; quickly tweak the mode-line size to make separators look not too crappy.
       dotspacemacs-default-font '("Terminus"
                                   :size ${toString fontSize}
                                   :weight normal
                                   :width normal
                                   :powerline-scale 1.1)

       ) ;; eof


    '';

    home.file.".spacemacs.d/hook-layers.el".text = ''
      ;; -*- mode: emacs-lisp -*-
      ;; just add (load "~/.spacemacs.d/hook-layers.el") in your dotspacemacs/layers function

      (let
        ((user-layers dotspacemacs-configuration-layers))
        (setq
          dotspacemacs-configuration-layers
            (append user-layers
              '( python
                 ansible
                 rust
                 windows-scripts
                 javascript
                 typescript
                 html
                 yaml
                 auto-completion
                 git
                 markdown
                 restclient
                 emacs-lisp
                 nixos
                 spell-checking
                 syntax-checking
                 systemd
                 lua
                 terraform
                 graphviz
                 c-c++
                 ;; (haskell :variables
                 ;;  haskell-enable-hindent t
                 ;;  haskell-completion-backend 'lsp
                 ;;  haskell-enable-hindent-style "gibiansky"
                 ;;  haskell-process-type 'cabal-new-repl)
               ))))

      (let
        ((user-packages dotspacemacs-additional-packages ))
        (setq
          dotspacemacs-additional-packages
            (append user-packages
              '(
                 ;; lsp-mode
                 ;; lsp-ui
                 ;; lsp-haskell
                 direnv
              ))))
    '';

    # a file which needs to be included at the end
    home.file.".spacemacs.d/hook-user-config.el".text = ''
      ;; -*- mode: emacs-lisp -*-
      ;; just add (load "~/.spacemacs.d/hook-user-config.el") in your dotspacemacs/user-config function


      ;; turn of smartparens mode off globally
      ;; https://github.com/Fuco1/smartparens
      ;;(spacemacs/toggle-smartparens-globally-off)
      ;;(remove-hook 'prog-mode-hook #'smartparens-mode)

       (setq powerline-default-separator 'nil)

      (let ((n 2))
        (setq coffee-tab-width n)
        (setq javascript-indent-level n)
        (setq js-indent-level n)
        (setq js2-basic-offset n)
        (setq web-mode-markup-indent-offset n)
        (setq web-mode-css-indent-offset n)
        (setq web-mode-code-indent-offset n)
        (setq css-indent-offset n))

      ;; configure indent function correctly
      (add-hook 'nix-mode-hook
                '(lambda ()
                   (setq indent-tabs-mode nil)
                   (setq tab-width 2)
                   (setq indent-line-function (quote nix-indent-line))))

      ;; lsp setup for haskell
      ;; hie-wrapper must be configured in the direnv setup
      ;; make sure cabal update was executed once on the machine
      ;; (setq lsp-haskell-process-path-hie "hie-wrapper")
      ;; (setq lsp-response-timeout 60)
      ;; (require 'lsp-haskell)
      ;; (add-hook 'haskell-mode-hook #'lsp)
      (add-hook 'haskell-mode-hook #'direnv-update-environment)

      ;; setup run-assoc
      ;; in dired mode use C-<RETURN> to open file in associated program
      (load "~/.spacemacs.d/run-assoc.el")
      (setq associated-program-alist
      '(
        ("${pkgs.evince}/bin/evince" "\\.pdf$")
        ("${pkgs.libreoffice}/bin/libreoffice" "\\.odt$")
        ("${pkgs.libreoffice}/bin/libreoffice" "\\.ods$")
        ${
          let
            suffixes = [ "jpg" "jpeg" "png" ];
            rule = suffix: ''("${pkgs.sxiv}/bin/sxiv" "\\.${suffix}$")'';
          in lib.concatStringsSep "\n  " (builtins.map rule suffixes)
        }
        ${
          let
            suffixes = [ "mp4" "mkv" "avi" ];
            rule = suffix: ''("${pkgs.mpv}/bin/mpv" "\\.${suffix}$")'';
          in lib.concatStringsSep "\n  " (builtins.map rule suffixes)
        }
        )
      )
    '';

    home.file.".spacemacs.d/run-assoc.el".source = pkgs.fetchurl {
      url = "https://www.emacswiki.org/emacs/download/run-assoc.el";
      sha256 = "1rg0pa09zfslgqnhbqvaa6vdi2fmanrpyzq67ppiin0h1kdgs4im";
    };

    home.file.".ctags.d/terraform.ctags".text = ''
      --langdef=terraform
      --langmap=terraform:.tf.tfvars
      --regex-terraform=/^[[:space:]]*resource[[:space:]]*"([^"]*)"[[:space:]]*"([^"]*)"/\1.\2/r,Resource/
      --regex-terraform=/^[[:space:]]*data[[:space:]]*"([^"]*)"[[:space:]]*"([^"]*)"/\1.\2/d,Data/
      --regex-terraform=/^[[:space:]]*variable[[:space:]]*"([^"]*)"/\1/v,Variable/
      --regex-terraform=/^[[:space:]]*provider[[:space:]]*"([^"]*)"/\1/p,Provider/
      --regex-terraform=/^[[:space:]]*module[[:space:]]*"([^"]*)"/\1/m,Module/
      --regex-terraform=/^[[:space:]]*output[[:space:]]*"([^"]*)"/\1/o,Output/
      --regex-terraform=/^([a-z0-9_]+)[[:space:]]*=/\1/f,TFVar/
    '';

    home.file.".spacemacs.d/old/polymode.el".text = ''
      ;; not used at the moment
      (define-hostmode poly-nix-hostmode
        :mode 'nix-mode)

      (define-innermode poly-nix-lisp-metadata-innermode
        :mode 'emacs-lisp-mode
        :head-matcher (rx "/* lisp */" (one-or-more space) ${ticks} (zero-or-more space) line-end)
        :tail-matcher (rx ${ticks} (zero-or-more space) ";" (zero-or-more space) line-end)
        :head-mode 'host
        :tail-mode 'host)

      (define-innermode poly-nix-shell-metadata-innermode
        :mode 'shell-script-mode
        :head-matcher (rx "/* sh */" (one-or-more space) ${ticks} (zero-or-more space) line-end)
        :tail-matcher (rx ${ticks} (zero-or-more space) ";" (zero-or-more space) line-end)
        :head-mode 'host
        :tail-mode 'host)

      (define-innermode poly-nix-python-metadata-innermode
        :mode 'python-mode
        :head-matcher (rx "/* python */" (one-or-more space) ${ticks} (zero-or-more space) line-end)
        :tail-matcher (rx ${ticks} (zero-or-more space) ";" (zero-or-more space) line-end)
        :head-mode 'host
        :tail-mode 'host)

      (define-innermode poly-nix-haskell-metadata-innermode
        :mode 'haskell-mode
        :head-matcher (rx "/* haskell */" (one-or-more space) ${ticks} (zero-or-more space) line-end)
        :tail-matcher (rx ${ticks} (zero-or-more space) ";" (zero-or-more space) line-end)
        :head-mode 'host
        :tail-mode 'host)

      (define-polymode poly-nix-mode
        :hostmode 'poly-nix-hostmode
        :innermodes '(poly-nix-lisp-metadata-innermode
                      poly-nix-shell-metadata-innermode
                      poly-nix-haskell-metadata-innermode
                      poly-nix-python-metadata-innermode))

      ;; remove nix-mode from auto load and replace it with poly-nix-mode
      (setq auto-mode-alist (rassq-delete-all 'nix-mode auto-mode-alist))
      (add-to-list 'auto-mode-alist '("\\.nix\\'" . poly-nix-mode))
    '';

  };
}