{
  config,
  lib,
  pkgs,
  self,
  flake,
  ...
}:
let
  configPy = pkgs.writeText "obs-portal-config.py" ''
    DEBUG = False
    VERBOSE = DEBUG
    AUTO_RESTART = DEBUG
    LEAN_MODE = False
    FRONTEND_URL = None
    FRONTEND_HTTPS = True
    FRONTEND_DIR = "../frontend/build/"
    FRONTEND_CONFIG = {
        "imprintUrl": "${config.pub-solar-os.imprintUrl}",
        "privacyPolicyUrl": "${config.pub-solar-os.privacyPolicyUrl}",
        "mapHome": {"zoom": 12, "latitude": 50.93, "longitude": 6.97},
        "banner": {
            "text": "This is an installation serving the Cologne/Bonn region run for Team OBSKöln by pub.solar n.e.V.",
            "style": "info"
        },
    }
    TILES_FILE = None
    ADDITIONAL_CORS_ORIGINS = None
  '';

  env = {
    OBS_KEYCLOAK_URI = "auth.${config.pub-solar-os.networking.domain}";
    OBS_PORTAL_URI = "obs-portal.${config.pub-solar-os.networking.domain}";

    OBS_POSTGRES_MAX_OVERFLOW = "20";
    OBS_POSTGRES_POOL_SIZE = "40";

    OBS_HOST = "0.0.0.0";
    OBS_PORT = "3000";
    OBS_KEYCLOAK_URL = "https://auth.${config.pub-solar-os.networking.domain}/realms/${config.pub-solar-os.auth.realm}/";
    OBS_KEYCLOAK_CLIENT_ID = "openbikesensor-portal";
    OBS_DEDICATED_WORKER = "True";
    OBS_DATA_DIR = "/data";
    OBS_PROXIES_COUNT = "1";
  };
in
{
  age.secrets.obs-portal-env = {
    file = "${flake.self}/secrets/obs-portal-env.age";
    mode = "600";
  };

  age.secrets.obs-portal-database-env = {
    file = "${flake.self}/secrets/obs-portal-database-env.age";
    mode = "600";
  };

  systemd.services."docker-network-obs-portal" =
    let
      docker = config.virtualisation.oci-containers.backend;
      dockerBin = "${pkgs.${docker}}/bin/${docker}";
    in
    {
      serviceConfig.Type = "oneshot";
      before = [
        "docker-obs-portal.service"
        "docker-obs-portal-db.service"
        "docker-obs-portal-worker.service"
      ];
      requiredBy = [
        "docker-obs-portal.service"
        "docker-obs-portal-db.service"
        "docker-obs-portal-worker.service"
      ];
      script = ''
        ${dockerBin} network inspect obs-portal-net >/dev/null 2>&1 || ${dockerBin} network create obs-portal-net --subnet 172.20.0.0/24
      '';
    };

  services.nginx.virtualHosts."obs-portal.${config.pub-solar-os.networking.domain}" = {
    enableACME = true;
    forceSSL = true;

    locations."/" = {
      proxyWebsockets = true;
      extraConfig = ''
        proxy_pass http://127.0.0.1:3001;
        proxy_set_header Host $host;
      '';
    };
  };

  virtualisation = {
    oci-containers = {
      backend = "docker";

      containers."obs-portal" = {
        image = "git.pub.solar/pub-solar/obs-portal:latest";
        autoStart = true;
        ports = [ "127.0.0.1:3001:${env.OBS_PORT}" ];
        dependsOn = [
          "obs-portal-db"
          "obs-portal-worker"
        ];

        environment = env;
        environmentFiles = [ config.age.secrets.obs-portal-env.path ];

        volumes = [
          "${configPy}:/opt/obs/api/config.py"
          "/var/lib/obs-portal${env.OBS_DATA_DIR}:${env.OBS_DATA_DIR}"
          "/var/lib/obs-portal/pbf/:/pbf"
        ];

        extraOptions = [ "--network=obs-portal-net" ];
      };

      containers."obs-portal-worker" = {
        image = "git.pub.solar/pub-solar/obs-portal:latest";
        autoStart = true;

        cmd = [
          "python"
          "tools/process_track.py"
        ];

        environment = env;
        environmentFiles = [ config.age.secrets.obs-portal-env.path ];

        volumes = [
          "${configPy}:/opt/obs/api/config.py"
          "/var/lib/obs-portal${env.OBS_DATA_DIR}:${env.OBS_DATA_DIR}"
        ];

        extraOptions = [ "--network=obs-portal-net" ];
      };

      containers."obs-portal-db" = {
        image = "openmaptiles/postgis:7.0";
        autoStart = true;

        environmentFiles = [ config.age.secrets.obs-portal-database-env.path ];

        volumes = [ "/var/lib/postgres-obs-portal/data:/var/lib/postgresql/data" ];

        extraOptions = [ "--network=obs-portal-net" ];
      };
    };
  };
}