{
  config,
  lib,
  pkgs,
  ...
}:
with lib; let
  serviceInterface = import ../../lib/service-interface.nix {inherit lib;};

  cfg = config.homelab.services.loki;
  homelabCfg = config.homelab;

  # Service-specific options beyond the standard interface
  lokiServiceOptions = {
    # Storage configuration
    storage = {
      type = mkOption {
        type = types.enum ["filesystem" "s3" "gcs"];
        default = "filesystem";
        description = "Storage backend type";
      };

      filesystem = {
        directory = mkOption {
          type = types.str;
          default = "/var/lib/loki";
          description = "Directory for filesystem storage";
        };
      };

      s3 = {
        endpoint = mkOption {
          type = types.nullOr types.str;
          default = null;
          description = "S3 endpoint URL";
        };

        bucket = mkOption {
          type = types.nullOr types.str;
          default = null;
          description = "S3 bucket name";
        };

        region = mkOption {
          type = types.nullOr types.str;
          default = null;
          description = "S3 region";
        };

        accessKeyId = mkOption {
          type = types.nullOr types.str;
          default = null;
          description = "S3 access key ID";
        };

        secretAccessKey = mkOption {
          type = types.nullOr types.path;
          default = null;
          description = "Path to file containing S3 secret access key";
        };
      };
    };

    # Retention configuration
    retention = {
      period = mkOption {
        type = types.str;
        default = "168h"; # 7 days
        description = "Log retention period";
      };

      streamRetention = mkOption {
        type = types.listOf (types.submodule {
          options = {
            selector = mkOption {
              type = types.str;
              description = "Log stream selector";
              example = "{environment=\"development\"}";
            };
            priority = mkOption {
              type = types.int;
              description = "Rule priority (higher = more important)";
              default = 1;
            };
            period = mkOption {
              type = types.str;
              description = "Retention period for this stream";
              example = "24h";
            };
          };
        });
        default = [];
        description = "Per-stream retention rules";
      };
    };

    # Performance tuning
    limits = {
      rejectOldSamples = mkOption {
        type = types.bool;
        default = true;
        description = "Reject samples older than max age";
      };

      rejectOldSamplesMaxAge = mkOption {
        type = types.str;
        default = "168h";
        description = "Maximum age for samples";
      };

      ingestionRateMB = mkOption {
        type = types.int;
        default = 4;
        description = "Ingestion rate limit in MB/s per tenant";
      };

      ingestionBurstSizeMB = mkOption {
        type = types.int;
        default = 6;
        description = "Ingestion burst size in MB per tenant";
      };

      maxStreamsPerUser = mkOption {
        type = types.int;
        default = 10000;
        description = "Maximum number of streams per user";
      };

      maxLineSize = mkOption {
        type = types.str;
        default = "256KB";
        description = "Maximum line size";
      };
    };

    # Authentication
    auth = {
      enabled = mkOption {
        type = types.bool;
        default = false;
        description = "Enable authentication";
      };
    };

    # Extra configuration options
    extraConfig = mkOption {
      type = types.attrs;
      default = {};
      description = "Additional Loki configuration options";
    };

    # Data directory
    dataDir = mkOption {
      type = types.str;
      default = "/var/lib/loki";
      description = "Directory to store Loki data";
    };
  };

  # Build the Loki configuration
  lokiConfig =
    recursiveUpdate {
      # Server configuration
      server = {
        http_listen_port = cfg.port;
        grpc_listen_port = cfg.port + 1000; # e.g., 3100 -> 4100
        http_listen_address = "0.0.0.0";
        grpc_listen_address = "0.0.0.0";
        log_level = cfg.monitoring.extraLabels.log_level or "info";
      };

      # Authentication
      auth_enabled = cfg.auth.enabled;

      # Analytics
      analytics.reporting_enabled = false;

      # Common configuration for single-binary mode
      common = {
        ring = {
          instance_addr = "127.0.0.1";
          kvstore.store = "inmemory";
        };
        replication_factor = 1;
        path_prefix = cfg.dataDir;
      };

      # Schema configuration
      schema_config = {
        configs = [
          {
            from = "2020-05-15";
            store = "tsdb";
            object_store = cfg.storage.type;
            schema = "v13";
            index = {
              prefix = "index_";
              period = "24h";
            };
          }
        ];
      };

      # Storage configuration
      storage_config = mkMerge [
        # Filesystem storage
        (mkIf (cfg.storage.type == "filesystem") {
          filesystem.directory = "${cfg.storage.filesystem.directory}/chunks";
        })

        # S3 storage
        (mkIf (cfg.storage.type == "s3") {
          aws =
            {
              s3 = cfg.storage.s3.endpoint;
              bucketnames = cfg.storage.s3.bucket;
              region = cfg.storage.s3.region;
              access_key_id = cfg.storage.s3.accessKeyId;
            }
            // (optionalAttrs (cfg.storage.s3.secretAccessKey != null) {
              secret_access_key = "$__file{${cfg.storage.s3.secretAccessKey}}";
            });
        })
      ];

      # Limits configuration
      limits_config =
        {
          reject_old_samples = cfg.limits.rejectOldSamples;
          reject_old_samples_max_age = cfg.limits.rejectOldSamplesMaxAge;
          ingestion_rate_mb = cfg.limits.ingestionRateMB;
          ingestion_burst_size_mb = cfg.limits.ingestionBurstSizeMB;
          max_streams_per_user = cfg.limits.maxStreamsPerUser;
          max_line_size = cfg.limits.maxLineSize;

          # Retention configuration
          retention_period = cfg.retention.period;
        }
        // (optionalAttrs (cfg.retention.streamRetention != []) {
          retention_stream =
            map (rule: {
              selector = rule.selector;
              priority = rule.priority;
              period = rule.period;
            })
            cfg.retention.streamRetention;
        });

      # Table manager for retention
      table_manager = {
        retention_deletes_enabled = true;
        retention_period = cfg.retention.period;
      };

      # Compactor configuration
      compactor = {
        working_directory = "${cfg.dataDir}/compactor";
        # shared_store = cfg.storage.type;
        compaction_interval = "10m";
        # retention_enabled = true;
        # retention_delete_delay = "2h";
        # retention_delete_worker_count = 150;
      };

      # Query range configuration
      query_range = {
        results_cache = {
          cache = {
            embedded_cache = {
              enabled = true;
              max_size_mb = 100;
            };
          };
        };
      };

      # Frontend configuration
      frontend = {
        max_outstanding_per_tenant = 256;
        compress_responses = true;
      };

      # Query scheduler
      query_scheduler = {
        max_outstanding_requests_per_tenant = 256;
      };

      # Runtime configuration
      runtime_config = {
        file = "/etc/loki/runtime.yml";
      };
    }
    cfg.extraConfig;
in {
  options.homelab.services.loki = serviceInterface.mkServiceInterface {
    serviceName = "loki";
    defaultPort = 3100;
    defaultSubdomain = "loki";
    monitoringPath = "/metrics";
    healthCheckPath = "/ready";
    healthCheckConditions = [
      "[STATUS] == 200"
      "[RESPONSE_TIME] < 2000"
    ];
    serviceOptions = lokiServiceOptions;
  };

  config = serviceInterface.mkServiceConfig {
    inherit config cfg homelabCfg;
    serviceName = "loki";

    extraMonitoringLabels = {
      component = "log-aggregation";
      log_level = "info";
    };

    customHealthChecks = [
      {
        name = "loki-health";
        port = cfg.port;
        # https://grafana.com/docs/loki/latest/reference/loki-http-api/#status-endpoints
        path = "/loki/api/v1/status/buildinfo";
        interval = "30s";
        conditions = ["[STATUS] == 200"];
        group = "logging";
        labels = {
          service = "loki";
          component = "api";
        };
      }
    ];

    serviceConfig = mkMerge [
      {
        services.loki = {
          enable = true;
          dataDir = cfg.dataDir;
          configuration = lokiConfig;
        };

        # Ensure data directories exist
        systemd.tmpfiles.rules = [
          "d ${cfg.dataDir} 0755 loki loki -"
          "d ${cfg.dataDir}/chunks 0755 loki loki -"
          "d ${cfg.dataDir}/compactor 0755 loki loki -"
        ];

        # Runtime configuration file for dynamic updates
        environment.etc."loki/runtime.yml".text = ''
          # Runtime configuration for Loki
          # This file can be updated without restarting Loki
        '';
      }
    ];
  };
}
