{
  config,
  lib,
  pkgs,
  ...
}:
with lib; let
  globalConfig = config;
  settingsFormat = {
    type = with lib.types; let
      value =
        oneOf [int str]
        // {
          description = "INI-like atom (int or string)";
        };
      values =
        coercedTo value lib.singleton (listOf value)
        // {
          description = value.description + " or a list of them for duplicate keys";
        };
    in
      attrsOf values;
    generate = name: values:
      pkgs.writeText name (lib.generators.toKeyValue {listsAsDuplicateKeys = true;} values);
  };
in {
  imports = [
    ../nginx-base
    ./config.nix
  ];

  options.services.nginx.virtualHosts = mkOption {
    type = types.attrsOf (types.submodule ({config, ...}: let
      cfg = config.cgit;

      # These are the global options for this submodule, but for nicer UX they
      # are inlined into the freeform settings.  Hence they MUST NOT INTERSECT
      # with any settings from cgitrc!
      options = {
        enable = mkEnableOption "cgit";

        location = mkOption {
          default = "/";
          type = types.str;
          description = ''
            Location to serve cgit on.
          '';
        };
      };

      # Remove the global options for serialization into cgitrc
      settings = removeAttrs cfg (attrNames options);
    in {
      options.cgit = mkOption {
        type = types.submodule {
          freeformType = settingsFormat.type;
          inherit options;
          config = {
            css = mkDefault "/cgit.css";
            logo = mkDefault "/cgit.png";
            favicon = mkDefault "/favicon.ico";
          };
        };
        default = {};
        example = literalExample ''
          {
            enable = true;
            virtual-root = "/";
            source-filter = "''${pkgs.cgit-pink}/lib/cgit/filters/syntax-highlighting.py";
            about-filter = "''${pkgs.cgit-pink}/lib/cgit/filters/about-formatting.sh";
            cache-size = 1000;
            scan-path = "/srv/git";
            include = [
              (builtins.toFile "cgitrc-extra-1" '''
                # Anything that has to be in a particular order
              ''')
              (builtins.toFile "cgitrc-extra-2" '''
                # Anything that has to be in a particular order
              ''')
            ];
          }
        '';
        description = ''
          Verbatim contents of the cgit runtime configuration file. Documentation
          (with cgitrc example file) is available in "man cgitrc". Or online:
          http://git.zx2c4.com/cgit/tree/cgitrc.5.txt
        '';
      };

      config = let
        location = removeSuffix "/" cfg.location;
      in
        mkIf cfg.enable {
          locations."${location}/" = {
            root = "${pkgs.cgit-pink}/cgit/";
            tryFiles = "$uri @cgit";
          };
          locations."~ ^${location}/(cgit.(css|png)|favicon.ico|robots.txt)$" = {
            alias = "${pkgs.cgit-pink}/cgit/$1";
          };
          locations."~ ^${location}/custom.css$" = {
            alias = ./custom.css;
          };
          locations."@cgit" = {
            extraConfig =
              ''
                include ${pkgs.nginx}/conf/fastcgi_params;
                fastcgi_param   CGIT_CONFIG     ${settingsFormat.generate "cgitrc" settings};
                fastcgi_param   SCRIPT_FILENAME ${pkgs.cgit-pink}/cgit/cgit.cgi;
                fastcgi_param   QUERY_STRING    $args;
                fastcgi_param   HTTP_HOST       $server_name;
                fastcgi_pass    unix:${globalConfig.services.fcgiwrap.socketAddress};
              ''
              + (
                if cfg.location == "/"
                then ''
                  fastcgi_param   PATH_INFO   $uri;
                ''
                else ''
                  fastcgi_split_path_info  ^(${location}/)(/?.+)$;
                  fastcgi_param  PATH_INFO  $fastcgi_path_info;
                ''
              );
          };
        };
    }));
  };

  config = let
    vhosts = config.services.nginx.virtualHosts;
  in
    mkIf (any (name: vhosts.${name}.cgit.enable) (attrNames vhosts)) {
      # make the cgitrc manpage available
      environment.systemPackages = [pkgs.cgit-pink];

      services.fcgiwrap.enable = true;
    };
}