{
  config,
  lib,
  nodes,
  ...
}:
with lib; let
  cfg = config.homelab.logging;
  homelabCfg = config.homelab;
  hasNodes = length (attrNames nodes) > 0;

  # Local aggregation
  localAggregation = {
    allSources =
      cfg.sources
      ++ (optional cfg.promtail.enable {
        name = "system-journal";
        type = "journal";
        journal.path = "/var/log/journal";
        labels =
          cfg.defaultLabels
          // {
            component = "system";
            log_source = "journald";
          };
        enabled = true;
      });
  };

  # Global aggregation
  globalAggregation = let
    baseAgg = import ../aggregators/base.nix {inherit lib;};

    sourcesAgg = baseAgg.aggregateFromNodes {
      inherit nodes;
      attributePath = "homelab.logging.allSources";
      enhancer = source:
        source
        // {
          _sourceNode = source._nodeName;
          _logId = "${source._nodeName}-${source.name}";
        };
    };
  in {
    allSources = sourcesAgg.all;
    sourcesByType = groupBy (s: s.type) sourcesAgg.all;
    summary = {
      total = length sourcesAgg.all;
      byType = sourcesAgg.countBy (s: s.type);
      byNode = sourcesAgg.countBy (s: s._nodeName);
    };
  };
in {
  options.homelab.logging = {
    enable = mkEnableOption "logging system";

    promtail = {
      enable = mkOption {
        type = types.bool;
        default = true;
      };
      port = mkOption {
        type = types.port;
        default = 9080;
      };
      clients = mkOption {
        type = types.listOf (types.submodule {
          options = {
            url = mkOption {type = types.str;};
            tenant_id = mkOption {
              type = types.nullOr types.str;
              default = null;
            };
          };
        });
        default = [{url = "http://monitor.${homelabCfg.domain}:3100/loki/api/v1/push";}];
      };
    };

    sources = mkOption {
      type = types.listOf (types.submodule {
        options = {
          name = mkOption {type = types.str;};
          type = mkOption {
            type = types.enum ["journal" "file" "syslog" "docker"];
            default = "file";
          };
          files = mkOption {
            type = types.submodule {
              options = {
                paths = mkOption {
                  type = types.listOf types.str;
                  default = [];
                };
                multiline = mkOption {
                  type = types.nullOr types.attrs;
                  default = null;
                };
              };
            };
            default = {};
          };
          journal = mkOption {
            type = types.submodule {
              options = {
                path = mkOption {
                  type = types.str;
                  default = "/var/log/journal";
                };
              };
            };
            default = {};
          };
          labels = mkOption {
            type = types.attrsOf types.str;
            default = {};
          };
          pipelineStages = mkOption {
            type = types.listOf types.attrs;
            default = [];
          };
          enabled = mkOption {
            type = types.bool;
            default = true;
          };
        };
      });
      default = [];
    };

    defaultLabels = mkOption {
      type = types.attrsOf types.str;
      default = {
        hostname = homelabCfg.hostname;
        environment = homelabCfg.environment;
        location = homelabCfg.location;
      };
    };

    # Always exposed aggregated data
    allSources = mkOption {
      type = types.listOf types.attrs;
      default = localAggregation.allSources;
      readOnly = true;
    };

    global = mkOption {
      type = types.attrs;
      default = globalAggregation;
      readOnly = true;
    };
  };

  config = mkIf cfg.enable {
    # Local setup
    services.promtail = mkIf cfg.promtail.enable {
      enable = true;
      configuration = {
        server = {
          http_listen_port = cfg.promtail.port;
          grpc_listen_port = 0;
        };
        positions.filename = "/var/lib/promtail/positions.yaml";
        clients = cfg.promtail.clients;
        scrape_configs = map (source:
          {
            job_name = source.name;
            static_configs = [
              {
                targets = ["localhost"];
                labels =
                  cfg.defaultLabels
                  // source.labels
                  // (
                    if source.type == "file"
                    then {
                      __path__ = concatStringsSep "," source.files.paths;
                    }
                    else {}
                  );
              }
            ];
            # pipeline_stages = source.pipelineStages;
          }
          // (
            if source.type == "journal"
            then {
              journal = {
                path = source.journal.path;
                labels = cfg.defaultLabels // source.labels;
              };
            }
            else {}
          ))
        localAggregation.allSources;
      };
    };

    networking.firewall.allowedTCPPorts = optionals cfg.promtail.enable [cfg.promtail.port];

    # homelab.logging = {
    #   allSources = localAggregation.allSources;
    #   global =
    #     if hasNodes
    #     then globalAggregation
    #     else {};
    # };
  };
}
