import ../../make-test-python.nix (
  { lib, pkgs, ... }:

  let
    inherit (lib) mkMerge maintainers;

    baseGrafanaConf = {
      services.grafana = {
        enable = true;
        provision.enable = true;
        settings = {
          analytics.reporting_enabled = false;

          server = {
            http_addr = "::1";
            domain = "localhost";
          };

          security = {
            admin_user = "testadmin";
            admin_password = "$__file{${pkgs.writeText "pwd" "snakeoilpwd"}}";
          };
        };
      };

      systemd.tmpfiles.rules =
        let
          dashboard = pkgs.writeText "test.json" (builtins.readFile ./test_dashboard.json);
        in
        [
          "d /var/lib/grafana/dashboards 0700 grafana grafana -"
          "C+ /var/lib/grafana/dashboards/test.json - - - - ${dashboard}"
        ];
    };

    extraNodeConfs = {
      provisionNix = {
        services.grafana.provision = {
          datasources.settings = {
            apiVersion = 1;
            datasources = [
              {
                name = "Test Datasource";
                type = "testdata";
                access = "proxy";
                uid = "test_datasource";
              }
            ];
          };

          dashboards.settings = {
            apiVersion = 1;
            providers = [
              {
                name = "default";
                options.path = "/var/lib/grafana/dashboards";
              }
            ];
          };

          alerting = {
            rules.settings = {
              groups = [
                {
                  name = "test_rule_group";
                  folder = "test_folder";
                  interval = "60s";
                  rules = [
                    {
                      uid = "test_rule";
                      title = "Test Rule";
                      condition = "A";
                      data = [
                        {
                          refId = "A";
                          datasourceUid = "-100";
                          model = {
                            conditions = [
                              {
                                evaluator = {
                                  params = [ 3 ];
                                  type = "git";
                                };
                                operator.type = "and";
                                query.params = [ "A" ];
                                reducer.type = "last";
                                type = "query";
                              }
                            ];
                            datasource = {
                              type = "__expr__";
                              uid = "-100";
                            };
                            expression = "1==0";
                            intervalMs = 1000;
                            maxDataPoints = 43200;
                            refId = "A";
                            type = "math";
                          };
                        }
                      ];
                      for = "60s";
                    }
                  ];
                }
              ];
            };

            contactPoints.settings = {
              contactPoints = [
                {
                  name = "Test Contact Point";
                  receivers = [
                    {
                      uid = "test_contact_point";
                      type = "prometheus-alertmanager";
                      settings.url = "http://localhost:9000";
                    }
                  ];
                }
              ];
            };

            policies.settings = {
              policies = [
                {
                  receiver = "Test Contact Point";
                }
              ];
            };

            templates.settings = {
              templates = [
                {
                  name = "Test Template";
                  template = "Test message";
                }
              ];
            };

            muteTimings.settings = {
              muteTimes = [
                {
                  name = "Test Mute Timing";
                }
              ];
            };
          };
        };
      };

      provisionYaml = {
        services.grafana.provision = {
          datasources.path = ./datasources.yaml;
          dashboards.path = ./dashboards.yaml;
          alerting = {
            rules.path = ./rules.yaml;
            contactPoints.path = ./contact-points.yaml;
            policies.path = ./policies.yaml;
            templates.path = ./templates.yaml;
            muteTimings.path = ./mute-timings.yaml;
          };
        };
      };

      provisionYamlDirs =
        let
          mkdir = p: pkgs.writeTextDir (baseNameOf p) (builtins.readFile p);
        in
        {
          services.grafana.provision = {
            datasources.path = mkdir ./datasources.yaml;
            dashboards.path = mkdir ./dashboards.yaml;
            alerting = {
              rules.path = mkdir ./rules.yaml;
              contactPoints.path = mkdir ./contact-points.yaml;
              policies.path = mkdir ./policies.yaml;
              templates.path = mkdir ./templates.yaml;
              muteTimings.path = mkdir ./mute-timings.yaml;
            };
          };
        };
    };

    nodes = builtins.mapAttrs (
      _: val:
      mkMerge [
        val
        baseGrafanaConf
      ]
    ) extraNodeConfs;
  in
  {
    name = "grafana-provision";

    meta.maintainers = [ ];

    inherit nodes;

    testScript = ''
      start_all()

      nodeNix = ("Nix (new format)", provisionNix)
      nodeYaml = ("Nix (YAML)", provisionYaml)
      nodeYamlDir = ("Nix (YAML in dirs)", provisionYamlDirs)

      for description, machine in [nodeNix, nodeYaml, nodeYamlDir]:
          with subtest(f"Should start provision node: {description}"):
              machine.wait_for_unit("grafana.service")
              machine.wait_for_open_port(3000, addr="::1")

          with subtest(f"Successful datasource provision with {description}"):
              machine.wait_until_succeeds(
                  "curl -sSfN -u testadmin:snakeoilpwd http://[::1]:3000/api/datasources/uid/test_datasource | grep Test\ Datasource"
              )

          with subtest(f"Successful dashboard provision with {description}"):
              machine.wait_until_succeeds(
                  "curl -sSfN -u testadmin:snakeoilpwd http://[::1]:3000/api/dashboards/uid/test_dashboard | grep Test\ Dashboard"
              )

          with subtest(f"Successful rule provision with {description}"):
              machine.wait_until_succeeds(
                  "curl -sSfN -u testadmin:snakeoilpwd http://[::1]:3000/api/v1/provisioning/alert-rules/test_rule | grep Test\ Rule"
              )

          with subtest(f"Successful contact point provision with {description}"):
              machine.wait_until_succeeds(
                  "curl -sSfN -u testadmin:snakeoilpwd http://[::1]:3000/api/v1/provisioning/contact-points | grep Test\ Contact\ Point"
              )

          with subtest(f"Successful policy provision with {description}"):
              machine.wait_until_succeeds(
                  "curl -sSfN -u testadmin:snakeoilpwd http://[::1]:3000/api/v1/provisioning/policies | grep Test\ Contact\ Point"
              )

          with subtest(f"Successful template provision with {description}"):
              machine.wait_until_succeeds(
                  "curl -sSfN -u testadmin:snakeoilpwd http://[::1]:3000/api/v1/provisioning/templates | grep Test\ Template"
              )

          with subtest("Successful mute timings provision with {description}"):
              machine.wait_until_succeeds(
                  "curl -sSfN -u testadmin:snakeoilpwd http://[::1]:3000/api/v1/provisioning/mute-timings | grep Test\ Mute\ Timing"
              )
    '';
  }
)
