{
  config,
  lib,
  pkgs,
  ...
}:
with lib; let
  cfg = config.homelab.services.grafana;
  homelabCfg = config.homelab;

  # Dashboard provisioning
  provisionDashboard = name: source: {
    "grafana-dashboards/${name}.json" = {
      inherit source;
      user = "grafana";
      group = "grafana";
      mode = "0644";
    };
  };

  # Generate all dashboard files
  dashboardFiles =
    fold (
      dashboard: acc:
        acc // (provisionDashboard dashboard.name dashboard.source)
    ) {}
    cfg.dashboards.files;
in {
  options.homelab.services.grafana = {
    enable = mkEnableOption "Grafana dashboard service";

    port = mkOption {
      type = types.port;
      default = 3000;
      description = "Port for Grafana web interface";
    };

    openFirewall = mkOption {
      type = types.bool;
      default = true;
      description = "Whether to open firewall ports";
    };

    dataDir = mkOption {
      type = types.str;
      default = "/var/lib/grafana";
      description = "Directory to store Grafana data";
    };

    domain = mkOption {
      type = types.str;
      default = "grafana.${homelabCfg.externalDomain}";
      description = "Domain for Grafana";
    };

    rootUrl = mkOption {
      type = types.str;
      default = "https://grafana.${homelabCfg.externalDomain}";
      description = "Root URL for Grafana";
    };

    # Authentication settings
    auth = {
      disableLoginForm = mkOption {
        type = types.bool;
        default = false;
        description = "Disable the login form";
      };

      oauthAutoLogin = mkOption {
        type = types.bool;
        default = false;
        description = "Enable OAuth auto-login";
      };

      genericOauth = {
        enabled = mkOption {
          type = types.bool;
          default = false;
          description = "Enable generic OAuth";
        };
      };
    };

    # Data source configuration
    datasources = {
      prometheus = {
        enable = mkOption {
          type = types.bool;
          default = true;
          description = "Enable Prometheus datasource";
        };

        url = mkOption {
          type = types.str;
          default = "http://127.0.0.1:9090";
          description = "Prometheus URL";
        };

        uid = mkOption {
          type = types.str;
          default = "prometheus";
          description = "Unique identifier for Prometheus datasource";
        };
      };

      loki = {
        enable = mkOption {
          type = types.bool;
          default = false;
          description = "Enable Loki datasource";
        };

        url = mkOption {
          type = types.str;
          default = "http://127.0.0.1:3100";
          description = "Loki URL";
        };

        uid = mkOption {
          type = types.str;
          default = "loki";
          description = "Unique identifier for Loki datasource";
        };
      };

      influxdb = {
        enable = mkOption {
          type = types.bool;
          default = false;
          description = "Enable InfluxDB datasource";
        };

        url = mkOption {
          type = types.str;
          default = "http://127.0.0.1:8086";
          description = "InfluxDB URL";
        };

        database = mkOption {
          type = types.str;
          default = "homelab";
          description = "InfluxDB database name";
        };

        tokenPath = mkOption {
          type = types.nullOr types.path;
          default = null;
          description = "Path to InfluxDB token file";
        };

        uid = mkOption {
          type = types.str;
          default = "influxdb";
          description = "Unique identifier for InfluxDB datasource";
        };
      };

      extra = mkOption {
        type = types.listOf types.attrs;
        default = [];
        description = "Additional data sources";
      };
    };

    # Dashboard configuration
    dashboards = {
      path = mkOption {
        type = types.str;
        default = "/etc/grafana-dashboards";
        description = "Path to dashboard files";
      };

      files = mkOption {
        type = types.listOf (types.submodule {
          options = {
            name = mkOption {
              type = types.str;
              description = "Dashboard name (without .json extension)";
              example = "node-exporter";
            };
            source = mkOption {
              type = types.path;
              description = "Path to dashboard JSON file";
            };
          };
        });
        default = [];
        description = "Dashboard files to provision";
        example = literalExpression ''
          [
            {
              name = "node-exporter";
              source = ./dashboards/node-exporter.json;
            }
            {
              name = "traefik";
              source = ./dashboards/traefik.json;
            }
          ]
        '';
      };
    };

    # Extra user groups for accessing secrets
    extraGroups = mkOption {
      type = types.listOf types.str;
      default = [];
      description = "Additional groups for the grafana user";
      example = ["influxdb2"];
    };

    # Additional settings
    extraSettings = mkOption {
      type = types.attrs;
      default = {};
      description = "Additional Grafana settings";
    };

    plugins = mkOption {
      type = types.listOf types.package;
      default = [];
      description = "Grafana plugins to install";
      example = literalExpression "with pkgs.grafanaPlugins; [ grafana-piechart-panel ]";
    };
  };

  config = mkIf cfg.enable {
    # Add grafana user to extra groups (e.g., for accessing secrets)
    users.users.grafana.extraGroups = cfg.extraGroups;

    services.grafana = {
      enable = true;
      dataDir = cfg.dataDir;
      declarativePlugins = cfg.plugins;

      settings =
        recursiveUpdate {
          server = {
            http_port = cfg.port;
            http_addr = "0.0.0.0";
            domain = cfg.domain;
            root_url = cfg.rootUrl;
            oauth_auto_login = cfg.auth.oauthAutoLogin;
          };

          "auth.generic_oauth" = {
            enabled = cfg.auth.genericOauth.enabled;
          };

          auth = {
            disable_login_form = cfg.auth.disableLoginForm;
          };
        }
        cfg.extraSettings;

      provision = {
        enable = true;

        datasources.settings = {
          datasources = let
            # Build datasource list
            datasources =
              []
              ++ optional cfg.datasources.prometheus.enable {
                uid = cfg.datasources.prometheus.uid;
                name = "Prometheus";
                type = "prometheus";
                url = cfg.datasources.prometheus.url;
              }
              ++ optional cfg.datasources.loki.enable {
                uid = cfg.datasources.loki.uid;
                name = "Loki";
                type = "loki";
                url = cfg.datasources.loki.url;
              }
              ++ optional cfg.datasources.influxdb.enable {
                uid = cfg.datasources.influxdb.uid;
                name = "InfluxDB";
                type = "influxdb";
                url = cfg.datasources.influxdb.url;
                access = "proxy";
                jsonData = {
                  dbName = cfg.datasources.influxdb.database;
                  httpHeaderName1 = "Authorization";
                };
                secureJsonData = mkIf (cfg.datasources.influxdb.tokenPath != null) {
                  httpHeaderValue1 = "$__file{${cfg.datasources.influxdb.tokenPath}}";
                };
              }
              ++ cfg.datasources.extra;
          in
            datasources;
        };

        dashboards.settings.providers = mkIf (cfg.dashboards.files != []) [
          {
            name = "homelab-dashboards";
            options.path = cfg.dashboards.path;
          }
        ];
      };
    };

    # Open firewall if requested
    networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [cfg.port];

    # Provision dashboard files
    environment.etc = dashboardFiles;

    # Add to monitoring endpoints
    homelab.monitoring.metrics = [
      {
        name = "grafana";
        port = cfg.port;
        path = "/metrics";
        jobName = "grafana";
        labels = {
          service = "grafana";
          component = "monitoring";
        };
      }
    ];

    # Add health checks
    homelab.monitoring.healthChecks = [
      {
        name = "grafana-web-interface";
        port = cfg.port;
        path = "/api/health";
        interval = "30s";
        conditions = [
          "[STATUS] == 200"
          "[BODY].database == ok"
          "[RESPONSE_TIME] < 2000"
        ];
        group = "monitoring";
        labels = {
          service = "grafana";
          component = "web-interface";
        };
      }
      {
        name = "grafana-login-page";
        port = cfg.port;
        path = "/login";
        interval = "60s";
        conditions = [
          "[STATUS] == 200"
          "[RESPONSE_TIME] < 3000"
        ];
        group = "monitoring";
        labels = {
          service = "grafana";
          component = "login";
        };
      }
    ];

    # Add reverse proxy entry
    homelab.reverseProxy.entries = [
      {
        subdomain = "grafana";
        host = homelabCfg.hostname;
        port = cfg.port;
      }
    ];
  };
}
