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

let
  cfg = config.services.flask_hello;
  domain = config.networking.domain;
  fqdn = if (cfg.nginx.subdomain != "") then "${cfg.nginx.subdomain}.${domain}" else domain;

  python-with-packages = pkgs.python3.withPackages (
    p: with p; [
      flask
    ]
  );

  inherit (lib)
    concatStringsSep
    getExe
    mkDefault
    mkEnableOption
    mkIf
    mkOption
    mkPackageOption
    types
    ;
in
{
  options.services.flask_hello = {
    enable = mkEnableOption "Flask Hello World service.";

    package = mkPackageOption pkgs "flask_hello" { };

    port = mkOption {
      type = types.port;
      default = 5000;
      description = "The port to listen on.";
    };

    user = mkOption {
      type = types.str;
      description = "The user the Flask service will run as.";
      default = "flaskapp";
    };

    group = mkOption {
      type = types.str;
      description = "The group the Flask service will run as.";
      default = "flaskapp";
    };

    nginx = {
      enable = mkOption {
        type = types.bool;
        default = true;
        description = "Enable Nginx as a reverse proxy for the Flask application.";
      };
      subdomain = mkOption {
        type = types.str;
        default = "flask_hello";
        description = "Subdomain for the Nginx virtual host. Leave empty for root domain.";
      };
      ssl = mkOption {
        type = types.bool;
        default = true;
        description = "Enable SSL for the Nginx virtual host using ACME.";
      };
    };

    gunicorn.extraArgs = mkOption {
      type = types.listOf types.str;
      default = [ ];
      description = "Extra arguments for gunicorn.";
    };
  };

  config = mkIf cfg.enable {
    nixpkgs.overlays = [ inputs.flask_hello.overlays.default ];

    networking.firewall.allowedTCPPorts = [
      80 # ACME challenge
      443
    ];

    systemd.services.flask_hello = {
      description = "Flask Hello World";
      after = [ "network.target" ];
      wantedBy = [ "multi-user.target" ];
      environment = {
        PYTHONPATH = "${python-with-packages}/${python-with-packages.sitePackages}";
      };
      serviceConfig = {
        ExecStart = ''
          ${getExe pkgs.python3Packages.gunicorn} \
            --bind=127.0.0.1:${toString cfg.port} \
            ${concatStringsSep " " cfg.gunicorn.extraArgs} \
            app:app
        '';
        WorkingDirectory = "${cfg.package}";
        Restart = "on-failure";
        User = cfg.user;
        Group = cfg.group;
      };
    };

    users.users."${cfg.user}" = {
      home = "/var/lib/${cfg.user}";
      isSystemUser = true;
      group = cfg.group;
    };
    users.groups."${cfg.group}" = { };

    services.nginx = mkIf cfg.nginx.enable {
      enable = mkDefault true;
      virtualHosts."${fqdn}" = {
        enableACME = cfg.nginx.ssl;
        forceSSL = cfg.nginx.ssl;
        locations."/".proxyPass = "http://127.0.0.1:${toString cfg.port}";
      };
    };

    security.acme = mkIf (cfg.nginx.enable && cfg.nginx.ssl) {
      acceptTerms = true;
      defaults.email = mkDefault "postmaster@${domain}";
      defaults.webroot = mkDefault "/var/lib/acme/acme-challenge";
      certs."${domain}".postRun = "systemctl reload nginx.service";
    };
  };
}
