{
  config,
  lib,
  pkgs,
  ...
}:
let
  inherit (lib)
    literalExpression
    mkIf
    mkOption
    mkChangedOptionModule
    mkRenamedOptionModule
    types
    ;

  cfg = config.programs.go;
  keyValueFormat = pkgs.formats.keyValue { };

  modeFileContent = "${cfg.telemetry.mode} ${cfg.telemetry.date}";
in
{
  meta.maintainers = [ lib.maintainers.rvolosatovs ];

  imports = [
    (mkChangedOptionModule [ "programs" "go" "goPath" ] [ "programs" "go" "env" "GOPATH" ] (config: [
      "${config.home.homeDirectory}/${config.programs.go.goPath}"
    ]))

    (mkChangedOptionModule [ "programs" "go" "extraGoPaths" ] [ "programs" "go" "env" "GOPATH" ] (
      config:
      lib.mkOrder 1500 (map (x: "${config.home.homeDirectory}/${x}") config.programs.go.extraGoPaths)
    ))

    (mkChangedOptionModule [ "programs" "go" "goBin" ] [ "programs" "go" "env" "GOBIN" ] (
      config: "${config.home.homeDirectory}/${config.programs.go.goBin}"
    ))

    (mkRenamedOptionModule [ "programs" "go" "goPrivate" ] [ "programs" "go" "env" "GOPRIVATE" ])
  ];

  options = {
    programs.go = {
      enable = lib.mkEnableOption "Go";

      package = lib.mkPackageOption pkgs "go" { nullable = true; };

      packages = mkOption {
        type = with types; attrsOf path;
        default = { };
        example = literalExpression ''
          {
            "golang.org/x/text" = builtins.fetchGit "https://go.googlesource.com/text";
            "golang.org/x/time" = builtins.fetchGit "https://go.googlesource.com/time";
          }
        '';
        description = "Packages to add to GOPATH.";
      };

      env = mkOption {
        type = types.submodule {
          freeformType = with types; attrsOf str;
          options = {
            GOPATH = mkOption {
              type = with types; either str (listOf str);
              apply = x: lib.concatStringsSep ":" (lib.toList x);
              default = "";
              description = "List of directories that should be used by the Go tooling.";
            };
            GOPRIVATE = mkOption {
              type = with types; either str (listOf str);
              apply = x: lib.concatStringsSep "," (lib.toList x);
              default = "";
              description = ''
                Controls which modules the 'go' command considers to be private (not
                available publicly) and should therefore not use the proxy or checksum database.
              '';
            };
          };
        };
        default = { };
        example = lib.literalExpression ''
          {
            GOPATH = [
              "''${config.home.homeDirectory}/mygo"
              "/another/go"
              "/yet/another/go"
            ];

            GOPRIVATE = [
              "*.corp.example.com"
              "rsc.io/private"
            ];

            CXX = "g++";
            GCCGO = "gccgo";
            GOAMD64 = "v1";
            GOARCH = "amd64";
            GOAUTH = "netrc";
          };
        '';
        description = ''
          Environment variables for Go. All the available options
          can be found running 'go env'.
        '';
      };

      telemetry = mkOption {
        type = types.submodule {
          options = {
            mode = mkOption {
              type =
                with types;
                nullOr (enum [
                  "off"
                  "local"
                  "on"
                ]);
              default = null;
              description = "Go telemetry mode to be set.";
            };

            date = mkOption {
              type = types.str;
              default = "1970-01-01";
              description = ''
                The date indicating the date at which the modefile
                was updated, in YYYY-MM-DD format. It's used to
                reset the timeout before the next telemetry report
                is uploaded when telemetry mode is set to "on".
              '';
            };
          };
        };
        default = { };
        description = "Options to configure Go telemetry mode.";
      };
    };
  };

  config =
    let
      firstGoPath = lib.elemAt (lib.splitString ":" cfg.env.GOPATH) 0;
      finalEnv = lib.filterAttrs (_: v: v != "") cfg.env;
    in
    mkIf cfg.enable (
      lib.mkMerge [
        {
          assertions = [
            {
              assertion =
                cfg.packages != { } -> cfg.env.GOPATH != "" -> lib.hasPrefix config.home.homeDirectory firstGoPath;
              message = "The first element of `programs.go.env.GOPATH must be an absolute path that points to a directory inside ${config.home.homeDirectory} if `programs.go.packages` is set.";
            }
          ];
          home.packages = mkIf (cfg.package != null) [ cfg.package ];

          home.file = mkIf (cfg.packages != { }) (
            let
              mainGoPath = if (cfg.env.GOPATH != "") then firstGoPath else "go";

              mkSrc = n: v: { "${mainGoPath}/src/${n}".source = v; };
            in
            lib.mergeAttrsList (lib.mapAttrsToList mkSrc cfg.packages)
          );
        }

        (mkIf (cfg.env != { }) {
          xdg.configFile."go/env" = {
            enable = !pkgs.stdenv.hostPlatform.isDarwin;
            source = keyValueFormat.generate "go-env" finalEnv;
          };

          home.file."Library/Application Support/go/env" = {
            enable = pkgs.stdenv.hostPlatform.isDarwin;
            source = keyValueFormat.generate "go-env" finalEnv;
          };
        })

        (mkIf (cfg.telemetry.mode != null) {
          home.file."Library/Application Support/go/telemetry/mode" = {
            enable = pkgs.stdenv.hostPlatform.isDarwin;
            text = modeFileContent;
          };

          xdg.configFile."go/telemetry/mode" = {
            enable = !pkgs.stdenv.hostPlatform.isDarwin;
            text = modeFileContent;
          };
        })
      ]
    );
}
