{
  config,
  pkgs,
  lib,
  ...
}:
with lib; let
  name = "gitlab";
  cfg = config.services.skynet."${name}";

  domain_base = "${cfg.domain.base}.${cfg.domain.tld}";
  domain_full = "${cfg.domain.sub}.${domain_base}";
in {
  imports = [
  ];

  options.services.skynet."${name}" = {
    enable = mkEnableOption "Skynet Gitlab";

    domain = {
      tld = mkOption {
        type = types.str;
        default = "ie";
      };

      base = mkOption {
        type = types.str;
        default = "skynet";
      };

      sub = mkOption {
        type = types.str;
        default = name;
      };
    };

    user = mkOption {
      type = types.str;
      # changes teh ssh user
      default = "git";
    };

    ldap = {
      base = mkOption {
        type = types.str;
        default = "dc=skynet,dc=ie";
        description = lib.mdDoc "The base address in the ldap server";
      };
    };
  };

  config = mkIf cfg.enable {
    # delete all data
    # rm -rf /run/gitlab && rm -rf /var/gitlab && rm -rf /var/lib/postgresql  && rm -rf /run/gitlab && rm -rf /var/lib/redis-gitlab
    # find all data
    # grep -r --exclude-dir={docker,containers,log,sys,nix,proc}  gitlab /

    age.secrets.gitlab_pw = {
      file = ../../secrets/gitlab/pw.age;
      owner = cfg.user;
      group = cfg.user;
    };
    age.secrets.gitlab_secrets_db = {
      file = ../../secrets/gitlab/secrets_db.age;
      owner = cfg.user;
      group = cfg.user;
    };
    age.secrets.gitlab_secrets_secret = {
      file = ../../secrets/gitlab/secrets_secret.age;
      owner = cfg.user;
      group = cfg.user;
    };
    age.secrets.gitlab_secrets_otp = {
      file = ../../secrets/gitlab/secrets_otp.age;
      owner = cfg.user;
      group = cfg.user;
    };
    age.secrets.gitlab_secrets_jws = {
      file = ../../secrets/gitlab/secrets_jws.age;
      owner = cfg.user;
      group = cfg.user;
    };
    age.secrets.gitlab_db_pw = {
      file = ../../secrets/gitlab/db_pw.age;
      owner = cfg.user;
      group = cfg.user;
    };

    services.skynet.acme.domains = [
      "${cfg.domain.sub}.${cfg.domain.base}.${cfg.domain.tld}"
      # Lets Encrypt seems to have a 4 levels limit for certs
      "*.pages.${cfg.domain.base}.${cfg.domain.tld}"
    ];

    # using https://nixos.org/manual/nixos/stable/index.html#module-services-gitlab as a guide
    services.skynet.dns.records = [
      {
        record = cfg.domain.sub;
        r_type = "A";
        value = config.services.skynet.host.ip;
      }
      # for gitlab pages
      {
        record = "*.pages.${cfg.domain.base}.${cfg.domain.tld}.";
        r_type = "A";
        value = config.services.skynet.host.ip;
      }

      # for email
      {
        record = "${cfg.domain.sub}";
        r_type = "MX";
        value = ''10 ${domain_full}.'';
      }
      {
        record = config.services.skynet.host.ip;
        r_type = "PTR";
        value = "${cfg.domain.sub}.${cfg.domain.base}.${cfg.domain.tld}.";
      }
      {
        record = "${domain_full}.";
        r_type = "TXT";
        value = ''"v=spf1 a:gitlab.skynet.ie -all"'';
      }
      {
        record = "_dmarc.${domain_full}.";
        r_type = "TXT";
        value = ''"v=DMARC1; p=none"'';
      }
    ];

    networking.firewall.allowedTCPPorts = [
      # for git
      2222
    ];

    services.openssh.ports = [22 2222];

    services.nginx.virtualHosts = {
      # main site
      "${cfg.domain.sub}.${cfg.domain.base}.${cfg.domain.tld}" = {
        forceSSL = true;
        useACMEHost = "skynet";
        locations."/" = {
          proxyPass = "http://unix:/run/gitlab/gitlab-workhorse.socket";
          extraConfig = ''
            client_max_body_size 1000M;
          '';
        };
      };

      # pages
      "*.pages.${cfg.domain.base}.${cfg.domain.tld}" = {
        forceSSL = true;
        useACMEHost = "skynet";
        locations."/".proxyPass = "http://127.0.0.1:8091";
      };
    };

    # set a valid HELO address
    services.postfix = {
      hostname = lib.mkForce domain_full;
      origin = lib.mkForce domain_full;
      domain = lib.mkForce domain_base;
    };

    services.gitlab = {
      enable = true;

      databasePasswordFile = config.age.secrets.gitlab_db_pw.path;
      initialRootPasswordFile = config.age.secrets.gitlab_pw.path;
      https = true;
      host = "${cfg.domain.sub}.${cfg.domain.base}.${cfg.domain.tld}";
      port = 443;
      user = cfg.user;
      group = cfg.user;
      databaseUsername = cfg.user;

      pages = {
        # TODO: https://docs.gitlab.com/ee/administration/pages/index.html#add-the-domain-to-the-public-suffix-list
        enable = true;
        settings = {
          # these are just examples, not to use
          #artifacts-server = "http(s)://<services.gitlab.host>/api/v4"
          #gitlab-server = "http(s)://<services.gitlab.host>"
          pages-domain = "pages.${cfg.domain.base}.${cfg.domain.tld}";

          listen-http = [
            "127.0.0.1:8091"
          ];

          /*
          auth-client-id = "generated-id-xxxxxxx";
          auth-client-secret = { _secret = "/var/keys/auth-client-secret"; };
          auth-redirect-uri = "https://projects.example.com/auth";
          auth-secret = { _secret = "/var/keys/auth-secret"; };
          auth-server = "https://gitlab.example.com";
          */
        };
      };

      # use the local email client
      smtp.enable = true;

      secrets = {
        dbFile = config.age.secrets.gitlab_secrets_db.path;
        secretFile = config.age.secrets.gitlab_secrets_secret.path;
        otpFile = config.age.secrets.gitlab_secrets_otp.path;
        jwsFile = config.age.secrets.gitlab_secrets_jws.path;
      };
      extraConfig = {
        gitlab_shell = {
          ssh_port = 2222;
        };

        ldap = {
          enabled = true;
          servers = {
            main = {
              label = "Skynet";
              host = "account.skynet.ie";
              port = 636;
              uid = "uid";
              encryption = "simple_tls";
              active_directory = false;
              base = "ou=users,${cfg.ldap.base}";
              user_filter = "(memberOf=cn=skynet-users,ou=groups,${cfg.ldap.base}))";

              attributes = {
                username = "uid";
                email = "skMail";
                name = "cn";
              };

              group_base = "ou=groups,${cfg.ldap.base}";
              admin_group = "skynet-admins";

              sync_ssh_keys = "sshPublicKey";
            };
          };
        };

        pages = {
          # default for pages is set to 8090 but that leaves an "ugly" port in the url,
          # override it here to make it look good
          port = 80;
          #external_http = ["${config.services.skynet.host.ip}:80"];
        };
      };
    };
  };
}