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

with lib;
let
  cfg = config.sane.services.kiwix-serve;
in
{
  options = {
    sane.services.kiwix-serve = {
      enable = mkOption {
        default = false;
        type = types.bool;
      };
      package = mkOption {
        type = types.package;
        default = pkgs.kiwix-tools;
        defaultText = literalExpression "pkgs.kiwix-tools";
        description = lib.mdDoc ''
          The package that provides `bin/kiwix-serve`.
        '';
      };
      port = mkOption {
        type = types.port;
        default = 80;
        description = lib.mdDoc "Port number to listen on.";
      };
      listenAddress = mkOption {
        type = types.nullOr types.str;
        default = null;
        description = lib.mdDoc ''
          IP address to listen on. Listens on all available addresses if unspecified.
        '';
      };
      zimPaths = mkOption {
        type = types.nonEmptyListOf (types.either types.str types.path);
        description = lib.mdDoc "ZIM file path(s)";
      };
    };
  };

  config = mkIf cfg.enable {
    systemd.services.kiwix-serve = let
      maybeListenAddress = lib.optionals (cfg.listenAddress != null) ["-l" cfg.listenAddress];
      args = maybeListenAddress ++ ["-p" cfg.port] ++ cfg.zimPaths;
    in {
      description = "Deliver ZIM file(s) articles via HTTP";
      serviceConfig.ExecStart = "${cfg.package}/bin/kiwix-serve ${lib.escapeShellArgs args}";
      serviceConfig.Type = "simple";
      after = [ "network.target" ];
      wantedBy = [ "multi-user.target" ];

      # hardening (systemd-analyze security kiwix-serve)
      serviceConfig.LockPersonality = true;
      serviceConfig.MemoryDenyWriteExecute = true;
      serviceConfig.NoNewPrivileges = true;
      serviceConfig.PrivateDevices = true;
      serviceConfig.PrivateMounts = true;
      serviceConfig.PrivateTmp = true;
      serviceConfig.PrivateUsers = true;
      serviceConfig.ProcSubset = "pid";
      serviceConfig.ProtectClock = true;
      serviceConfig.ProtectControlGroups = true;
      serviceConfig.ProtectHome = true;
      serviceConfig.ProtectHostname = true;
      serviceConfig.ProtectKernelLogs = true;
      serviceConfig.ProtectKernelModules = true;
      serviceConfig.ProtectKernelTunables = true;
      serviceConfig.ProtectProc = "invisible";
      serviceConfig.ProtectSystem = "strict";
      serviceConfig.RemoveIPC = true;
      serviceConfig.ReadPaths = cfg.zimPaths;
      serviceConfig.RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6";
      serviceConfig.RestrictNamespaces = true;
      serviceConfig.RestrictSUIDSGID = true;
      serviceConfig.SystemCallArchitectures = "native";
      serviceConfig.SystemCallFilter = [ "@system-service" "~@privileged" "~@resources" ];
    };
  };
}
