serviceName: {
  config,
  lib,
  ...
}:
with lib; let
  cfg = config.homelab.services.${serviceName};
  homelabCfg = config.homelab;

  shouldEnableLogging =
    cfg.logging.files
    != []
    || cfg.logging.extraSources != [];
in {
  options.homelab.services.${serviceName}.logging = {
    enable = mkOption {
      type = types.bool;
      description = "Enable logging for ${serviceName}";
      default = shouldEnableLogging;
    };

    files = mkOption {
      type = types.listOf types.str;
      default = [];
    };

    parsing = {
      regex = mkOption {
        type = types.nullOr types.str;
        default = null;
      };

      extractFields = mkOption {
        type = types.listOf types.str;
        default = [];
      };
    };

    multiline = mkOption {
      type = types.nullOr (types.submodule {
        options = {
          firstLineRegex = mkOption {type = types.str;};
          maxWaitTime = mkOption {
            type = types.str;
            default = "3s";
          };
        };
      });
      default = null;
    };

    extraLabels = mkOption {
      type = types.attrsOf types.str;
      default = {};
    };

    extraSources = mkOption {
      type = types.listOf types.attrs;
      default = [];
    };
  };

  config = mkIf cfg.enable {
    homelab.logging.sources = mkIf cfg.logging.enable (
      # Only create file source if files are specified
      (optional (cfg.logging.files != []) {
        name = "${serviceName}-logs";
        type = "file";
        files = {
          paths = cfg.logging.files;
          multiline = cfg.logging.multiline;
        };
        labels =
          cfg.logging.extraLabels
          // {
            service = serviceName;
            node = homelabCfg.hostname;
            environment = homelabCfg.environment;
          };
        pipelineStages =
          (optional (cfg.logging.parsing.regex != null) {
            regex.expression = cfg.logging.parsing.regex;
          })
          ++ (optional (cfg.logging.parsing.extractFields != []) {
            labels = listToAttrs (map (field: nameValuePair field null) cfg.logging.parsing.extractFields);
          });
        enabled = true;
      })
      ++ cfg.logging.extraSources
    );
  };
}
