package azuremonitor

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/stretchr/testify/require"

	"github.com/grafana/grafana/pkg/api/dtos"
	"github.com/grafana/grafana/pkg/components/simplejson"
	"github.com/grafana/grafana/pkg/services/datasources"
	"github.com/grafana/grafana/pkg/services/org"
	"github.com/grafana/grafana/pkg/services/user"
	"github.com/grafana/grafana/pkg/tests/testinfra"
	"github.com/grafana/grafana/pkg/tests/testsuite"
	"github.com/grafana/grafana/pkg/util/testutil"
)

func TestMain(m *testing.M) {
	testsuite.Run(m)
}

func TestIntegrationAzureMonitor(t *testing.T) {
	testutil.SkipIntegrationTestInShortMode(t)

	t.Skip("skipping integration test due to flakiness")
	dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
		DisableAnonymous: true,
	})

	grafanaListeningAddr, testEnv := testinfra.StartGrafanaEnv(t, dir, path)
	ctx := context.Background()

	u := testinfra.CreateUser(t, testEnv.SQLStore, testEnv.Cfg, user.CreateUserCommand{
		DefaultOrgRole: string(org.RoleAdmin),
		Password:       "admin",
		Login:          "admin",
	})

	var outgoingRequest *http.Request
	outgoingServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		outgoingRequest = r
		w.WriteHeader(http.StatusUnauthorized)
	}))
	t.Cleanup(outgoingServer.Close)

	jsonData := simplejson.NewFromAny(map[string]any{
		"httpHeaderName1": "X-CUSTOM-HEADER",
		"clientId":        "test-client-id",
		"tenantId":        "test-tenant-id",
		"cloudName":       "customizedazuremonitor",
		"customizedRoutes": map[string]any{
			"Azure Monitor": map[string]any{
				"URL": outgoingServer.URL,
				"Headers": map[string]string{
					"custom-azure-header": "custom-azure-value",
				},
			},
		},
	})
	secureJSONData := map[string]string{
		"clientSecret":     "test-client-secret",
		"httpHeaderValue1": "custom-header-value",
	}

	uid := "azuremonitor"
	_, err := testEnv.Server.HTTPServer.DataSourcesService.AddDataSource(ctx, &datasources.AddDataSourceCommand{
		OrgID:          u.OrgID,
		Access:         datasources.DS_ACCESS_PROXY,
		Name:           "Azure Monitor",
		Type:           datasources.DS_AZURE_MONITOR,
		UID:            uid,
		URL:            outgoingServer.URL,
		JsonData:       jsonData,
		SecureJsonData: secureJSONData,
	})
	require.NoError(t, err)

	t.Run("When calling /api/ds/query should set expected headers on outgoing HTTP request", func(t *testing.T) {
		query := simplejson.NewFromAny(map[string]any{
			"datasource": map[string]any{
				"type": "grafana-azure-monitor-datasource",
				"uid":  uid,
			},
			"queryType": "Azure Monitor",
			"azureMonitor": map[string]any{
				"resourceGroup":   "test-rg",
				"metricNamespace": "microsoft.storage/storageaccounts",
				"resourceName":    "testacct",
				"timeGrain":       "auto",
				"metricName":      "UsedCapacity",
				"aggregation":     "Average",
			},
			"subscription": "test-sub",
			"intervalMs":   30000,
		})
		buf1 := &bytes.Buffer{}
		err = json.NewEncoder(buf1).Encode(dtos.MetricRequest{
			From:    "1668078080000",
			To:      "1668081680000",
			Queries: []*simplejson.Json{query},
		})
		require.NoError(t, err)
		u := fmt.Sprintf("http://admin:admin@%s/api/ds/query", grafanaListeningAddr)
		// nolint:gosec
		resp, err := http.Post(u, "application/json", buf1)
		require.NoError(t, err)
		require.Equal(t, http.StatusBadRequest, resp.StatusCode)
		t.Cleanup(func() {
			err := resp.Body.Close()
			require.NoError(t, err)
		})
		_, err = io.ReadAll(resp.Body)
		require.NoError(t, err)

		require.NotNil(t, outgoingRequest)
		require.Equal(t, "/subscriptions/test-sub/resourceGroups/test-rg/providers/microsoft.storage/storageaccounts/testacct/providers/microsoft.insights/metrics?aggregation=Average&api-version=2021-05-01&interval=PT1M&metricnames=UsedCapacity&metricnamespace=microsoft.storage%2Fstorageaccounts&timespan=2022-11-10T11%3A01%3A20Z%2F2022-11-10T12%3A01%3A20Z",
			outgoingRequest.URL.String())
		require.Equal(t, "custom-header-value", outgoingRequest.Header.Get("X-CUSTOM-HEADER"))
		require.Equal(t, "custom-azure-value", outgoingRequest.Header.Get("custom-azure-header"))
	})
}
