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

with lib;
let
  cfg = config.services.objectifier;

  pythonYolo = pkgs.python3.withPackages (pyPkgs:
    with pyPkgs; [
      fastapi
      gunicorn
      opencv4
      python-multipart
      uvicorn
    ]);

in {
  options.services.objectifier = with types; {
    enable = mkEnableOption "Enable Objectifier object-detection web sevice.";

    port = mkOption {
      type = port;
      description = "Port on which to run the Objectifier web service.";
      default = 5121;
    };

    workers = mkOption {
      type = int;
      description = "Number of worker threads to launch.";
      default = 3;
    };

    listen-addresses = mkOption {
      type = listOf str;
      description =
        "List of IP addresses on which to listen for incoming requests.";
      default = [ "127.0.0.1" ];
    };

    cleanup = {
      max_file_age = mkOption {
        type = int;
        description =
          "Maximum age of a file (in seconds), after which it will be removed.";
        default = (60 * 60 * 8); # 8 hours
      };

      delay = mkOption {
        type = int;
        description = "Time between cleanup sweeps.";
        default = (60 * 10); # 10 minutes
      };
    };
  };

  config = mkIf cfg.enable {
    systemd.services.objectifier = {
      after = [ "network-online.target" ];
      wantedBy = [ "multi-user.target" ];
      environment = {
        OBJECTIFIER_YOLOV3_CONFIG = "${pkgs.yolov3-data}/yolov3.cfg";
        OBJECTIFIER_YOLOV3_WEIGHTS = "${pkgs.yolov3-data}/yolov3.weights";
        OBJECTIFIER_YOLOV3_LABELS = "${pkgs.yolov3-data}/labels";
        OBJECTIFIER_BUFFER_SIZE = "524288";
        OBJECTIFIER_CLEANUP_MAX_AGE = toString cfg.cleanup.max_file_age;
        OBJECTIFIER_CLEANUP_DELAY = toString cfg.cleanup.delay;
      };
      serviceConfig = {
        # PrivateUsers = true;
        # PrivateDevices = true;
        # PrivateTmp = true;
        # PrivateMounts = true;
        # ProtectControlGroups = true;
        # ProtectKernelTunables = true;
        # ProtectKernelModules = true;
        # ProtectSystem = true;
        # ProtectHostname = true;
        # ProtectHome = true;
        # ProtectClock = true;
        # ProtectKernelLogs = true;
        # DynamicUser = true;
        # MemoryDenyWriteExecute = true;
        # RestrictRealtime = true;
        # LockPersonality = true;
        # PermissionsStartOnly = true;
        WorkingDirectory = "${pkgs.objectifier}";
        StateDirectory = "objectifier";
        CacheDirectory = "objectifier";
        LimitNOFILE = 4096;
        Restart = "on-failure";
        RestartSec = "5s";
        Type = "simple";
        PIDFile = "/run/objectifier.pid";
        ExecStart = let
          bindClause = concatStringsSep " "
            (map (addr: "--bind ${addr}:${toString cfg.port}")
              cfg.listen-addresses);
        in (concatStringsSep " " [
          "${pkgs.objectifier}/bin/objectifier"
          bindClause
          "--workers ${toString cfg.workers}"
          "--pid /run/objectifier.pid"
        ]);
      };
    };
  };
}