{ 
  inputs,
  flake,
  self,
}:
{ 
  pkgs,
  lib,
  config,
  ...
}: let
  system = pkgs.stdenv.hostPlatform.system;
  cfg    = config.hectic.services."sentinèlla";

  probePort = 5988;
  peersSrv  = "_sentinella._tcp.hectic-lab.com";
in {
  options = {
    hectic.services."sentinèlla" = {
      probe = {
        enable = lib.mkEnableOption "sentinèlla probe — HTTP server exposing this node's health";
        urls = lib.mkOption {
          type    = with lib.types; listOf str;
          default = [];
          description = "URLs the probe health-checks on GET /status.";
        };
        volumes = lib.mkOption {
          type    = with lib.types; listOf str;
          default = [];
          description = "Mount points reported on GET /disk. Empty means all volumes.";
        };
        authFile = lib.mkOption {
          type    = with lib.types; nullOr path;
          default = null;
          example = "config.sops.secrets.\"sentinella-probe-auth\".path";
          description = "Path to a file with lines of the form user:pass for Basic Auth.";
        };
        environmentFile = lib.mkOption {
          type    = with lib.types; nullOr path;
          default = null;
          description = ''
            Optional environment file for secrets. Supported variables:
              PORT=
              URLS=
              VOLUMES=
              AUTH_FILE=
          '';
        };
      };

      watcher = {
        enable = lib.mkEnableOption "sentinèlla watcher — polls peers discovered via DNS and sends Telegram alerts";
        self = lib.mkOption {
          type    = with lib.types; nullOr str;
          default = null;
          example = "1.2.3.4";
          description = ''
            Override the auto-detected local IP. When null (default) the watcher
            uses hostname -I to find all local IPs and excludes them from the
            peer list automatically. Set this only if the node is behind NAT or
            has a floating IP that hostname -I does not report correctly.
          '';
        };
        peersScheme = lib.mkOption {
          type    = lib.types.str;
          default = "http";
          description = "URL scheme used when connecting to peers (http or https).";
        };
        pollingIntervalSec = lib.mkOption {
          type    = lib.types.int;
          default = 3;
          description = "Seconds between polling rounds.";
        };
        tgToken = lib.mkOption {
          type    = with lib.types; nullOr str;
          default = null;
          description = "Telegram bot token. Prefer environmentFile for secrets.";
        };
        tgChatId = lib.mkOption {
          type    = with lib.types; nullOr str;
          default = null;
          description = "Telegram chat ID. Prefer environmentFile for secrets.";
        };
        environmentFile = lib.mkOption {
          type    = with lib.types; nullOr path;
          default = config.sops.secrets."sentinèlla/watcher/environment".path;
          defaultText = lib.literalExpression
            "config.sops.secrets.\"sentinèlla/watcher/environment\".path";
          example = "config.sops.secrets.\"sentinella-watcher-env\".path";
          description = ''
            Environment file for secrets. Defaults to the auto-declared SOPS
            secret sentinèlla/watcher/environment (resolved from
            sus/sentinella-default.yaml in the flake). Override the sopsFile
            via sops.secrets."sentinèlla/watcher/environment".sopsFile if you
            need a host-specific file instead.

            Supported variables:
              TG_TOKEN=
              TG_CHAT_ID=
              PEERS_TOKEN=   # Basic Auth token sent to all peers
              SELF=
              PEERS_SRV=
          '';
        };
      };
    };
  };

  config = lib.mkMerge [
    (lib.mkIf cfg.probe.enable {
      networking.firewall = {
        enable = true;
        allowedTCPPorts = [
          probePort     
        ];
      };

      systemd.services."sentinella-probe" = {
        description = "sentinèlla probe — node health HTTP server";
        after       = [ "network.target" ];
        wantedBy    = [ "multi-user.target" ];
        serviceConfig = lib.mkMerge [
          {
            Type            = "simple";
            ExecStart       = "${self.packages.${system}."sentinèlla"}/bin/probe";
            Restart         = "always";
            RestartSec      = "5s";
            TimeoutStopSec  = "30s";
            KillSignal      = "SIGTERM";
            KillMode        = "mixed";
            RemainAfterExit = false;
            StandardOutput  = "journal";
            StandardError   = "journal";
            Environment = lib.filter (s: s != "") [
              "PORT=${builtins.toString probePort}"
              (lib.optionalString (cfg.probe.urls    != []) "URLS=${lib.concatStringsSep " " cfg.probe.urls}")
              (lib.optionalString (cfg.probe.volumes != []) "VOLUMES=${lib.concatStringsSep " " cfg.probe.volumes}")
              (lib.optionalString (cfg.probe.authFile != null) "AUTH_FILE=${cfg.probe.authFile}")
            ];
          }
          (lib.mkIf (cfg.probe.environmentFile != null) {
            EnvironmentFile = cfg.probe.environmentFile;
          })
        ];
      };
    })

    (lib.mkIf cfg.watcher.enable {
      sops.secrets."sentinèlla/watcher/environment" = lib.mkDefault {
        sopsFile = "${flake}/sus/sentinella-default.yaml";
      };

      systemd.services."sentinella-watcher" = {
        description = "sentinèlla watcher — p2p peer monitor";
        after       = [ "network.target" ];
        wantedBy    = [ "multi-user.target" ];
        serviceConfig = lib.mkMerge [
          {
            Type            = "simple";
            ExecStart       = "${self.packages.${system}."sentinèlla"}/bin/watcher";
            Restart         = "always";
            RestartSec      = "5s";
            TimeoutStopSec  = "30s";
            KillSignal      = "SIGTERM";
            KillMode        = "mixed";
            RemainAfterExit = false;
            StandardOutput  = "journal";
            StandardError   = "journal";
            StateDirectory  = "sentinella";
            Environment = lib.filter (s: s != "") [
              "PEERS_SRV=${peersSrv}"
              (lib.optionalString (cfg.watcher.self != null) "SELF=${cfg.watcher.self}")
              "PEERS_SCHEME=${cfg.watcher.peersScheme}"
              "POLLING_INTERVAL_SEC=${builtins.toString cfg.watcher.pollingIntervalSec}"
              "STATE_DIR=/var/lib/sentinella"
              (lib.optionalString (cfg.watcher.tgToken  != null) "TG_TOKEN=${cfg.watcher.tgToken}")
              (lib.optionalString (cfg.watcher.tgChatId != null) "TG_CHAT_ID=${cfg.watcher.tgChatId}")
            ];
          }
          (lib.mkIf (cfg.watcher.environmentFile != null) {
            EnvironmentFile = cfg.watcher.environmentFile;
          })
        ];
      };
    })
  ];
}
