{ config, pkgs, ... }:

let
  mymqttui = pkgs.writeScriptBin "mqttui" ''
    export MQTTUI_USERNAME=consumer
    export MQTTUI_PASSWORD=`cat ${(builtins.head config.services.mosquitto.listeners).users.consumer.passwordFile}`
    exec ${pkgs.mqttui}/bin/mqttui
  '';

  fqdn = "broker.serv.zentralwerk.org";

  mqttWebsocketPort = 9001;
in
{
  c3d2.deployment.server = "server10";

  microvm.mem = 1024;

  networking = {
    hostName = "broker";
    firewall.allowedTCPPorts = [
      # mosquitto
      1883 8883
    ];
  };

  # runs mainly to obtain a TLS certificate
  services.nginx = {
    enable = true;
    virtualHosts.${fqdn} = {
      default = true;
      enableACME = true;
      forceSSL = true;
      locations."/mqtt" = {
        proxyPass = "http://localhost:${toString mqttWebsocketPort}/";
        proxyWebsockets = true;
      };
    };
  };

  services.mosquitto = {
    enable = true;
    listeners =
      let
        users = {
          "zentralwerk-network" = {
            passwordFile = config.sops.secrets."mosquitto/users/zentralwerk-network".path;
            acl = [
              "write #"
            ];
          };
          "services" = {
            passwordFile = config.sops.secrets."mosquitto/users/services".path;
            acl = [
              "write #"
            ];
          };
          "consumer" = {
            passwordFile = config.sops.secrets."mosquitto/users/consumer".path;
            acl = [
              "read #"
            ];
          };
          "sensors" = {
            passwordFile = config.sops.secrets."mosquitto/users/sensors".path;
            acl = [
              "write esp-sdk/#"
              "write esp-proc/#"
            ];
          };
        };
      in [ {
        address = "0.0.0.0";
        port = 1883;
        inherit users;
      } {
        address = "::";
        port = 1883;
        inherit users;
      } {
        address = "0.0.0.0";
        port = 8883;
        settings = {
          certfile = "/run/credentials/mosquitto.service/cert.pem";
          keyfile = "/run/credentials/mosquitto.service/key.pem";
        };
        inherit users;
      } {
        address = "::";
        port = 8883;
        settings = {
          certfile = "/run/credentials/mosquitto.service/cert.pem";
          keyfile = "/run/credentials/mosquitto.service/key.pem";
        };
        inherit users;
      } {
        settings.protocol = "websockets";
        address = "::";
        port = mqttWebsocketPort;
        inherit users;
      } ];
  };
  systemd.services.mosquitto = {
    requires = [ "acme-finished-${fqdn}.target" ];
    serviceConfig.LoadCredential =
      let
        certDir = config.security.acme.certs.${fqdn}.directory;
      in [
        "cert.pem:${certDir}/fullchain.pem"
        "key.pem:${certDir}/key.pem"
      ];
  };
  security.acme.certs.${fqdn}.postRun = ''
    systemctl restart mosquitto
  '';

  sops = {
    age.sshKeyPaths = [ "/etc/ssh/ssh_host_ed25519_key" ];
    defaultSopsFile = ./secrets.yaml;
    secrets = let
      perms = {
        owner = config.systemd.services.mosquitto.serviceConfig.User;
        group = config.systemd.services.mosquitto.serviceConfig.Group;
        mode = "0440";
      };
    in
    {
      "mosquitto/users/zentralwerk-network" = perms;
      "mosquitto/users/services" = perms;
      "mosquitto/users/consumer" = perms;
      "mosquitto/users/sensors" = perms;
    };
  };

  environment.systemPackages = with pkgs; [
    mymqttui
  ];

  users.motd = ''
    C3D2 MQTT Broker
    ================

    Use `mqttui` to inspect the data in mosquitto.

  '';

  system.stateVersion = "22.05";
}
