package models_test

import (
	"encoding/json"
	"sort"
	"testing"

	"github.com/pmezard/go-difflib/difflib"

	"github.com/prymitive/karma/internal/models"
)

func TestDedupSharedMaps(t *testing.T) {
	am := models.AlertmanagerInstance{
		Fingerprint: "1",
		Name:        "am",
		Cluster:     "fakeCluster",
		SilencedBy:  []string{"fakeSilence1", "fakeSilence2"},
	}
	ag := models.APIAlertGroup{
		AlertGroup: models.AlertGroup{
			Labels: map[string]string{
				"alertname": "FakeAlert",
			},
			Alerts: models.AlertList{
				models.Alert{
					State: models.AlertStateSuppressed,
					Annotations: models.Annotations{
						models.Annotation{
							Name:  "summary",
							Value: "this is summary",
						},
						models.Annotation{
							Name:  "foo",
							Value: "bar",
						},
					},
					Labels: map[string]string{
						"alertname": "FakeAlert",
						"job":       "node_exporter",
						"instance":  "1",
					},
					Alertmanager: []models.AlertmanagerInstance{am, am},
				},
				models.Alert{
					State: models.AlertStateSuppressed,
					Annotations: models.Annotations{
						models.Annotation{
							Name:  "summary",
							Value: "this is summary",
						},
					},
					Labels: map[string]string{
						"alertname": "FakeAlert",
						"job":       "node_exporter",
						"instance":  "2",
					},
					Alertmanager: []models.AlertmanagerInstance{am, am},
				},
				models.Alert{
					State: models.AlertStateSuppressed,
					Annotations: models.Annotations{
						models.Annotation{
							Name:  "summary",
							Value: "this is summary",
						},
					},
					Labels: map[string]string{
						"alertname": "FakeAlert",
						"job":       "blackbox",
						"instance":  "3",
					},
					Alertmanager: []models.AlertmanagerInstance{am, am},
				},
			},
		},
	}
	ag.DedupSharedMaps()

	expectedJSON := `{
  "receiver": "",
  "labels": {
    "alertname": "FakeAlert"
  },
  "alerts": [
    {
      "annotations": [
        {
          "name": "foo",
          "value": "bar",
          "visible": false,
          "isLink": false
        }
      ],
      "labels": {
        "instance": "1",
        "job": "node_exporter"
      },
      "startsAt": "0001-01-01T00:00:00Z",
      "state": "suppressed",
      "alertmanager": [
        {
          "fingerprint": "1",
          "name": "am",
          "cluster": "fakeCluster",
          "state": "",
          "startsAt": "0001-01-01T00:00:00Z",
          "source": "",
          "silencedBy": [
            "fakeSilence1",
            "fakeSilence2"
          ],
          "inhibitedBy": null
        },
        {
          "fingerprint": "1",
          "name": "am",
          "cluster": "fakeCluster",
          "state": "",
          "startsAt": "0001-01-01T00:00:00Z",
          "source": "",
          "silencedBy": [
            "fakeSilence1",
            "fakeSilence2"
          ],
          "inhibitedBy": null
        }
      ],
      "receiver": "",
      "id": ""
    },
    {
      "annotations": [],
      "labels": {
        "instance": "2",
        "job": "node_exporter"
      },
      "startsAt": "0001-01-01T00:00:00Z",
      "state": "suppressed",
      "alertmanager": [
        {
          "fingerprint": "1",
          "name": "am",
          "cluster": "fakeCluster",
          "state": "",
          "startsAt": "0001-01-01T00:00:00Z",
          "source": "",
          "silencedBy": [
            "fakeSilence1",
            "fakeSilence2"
          ],
          "inhibitedBy": null
        },
        {
          "fingerprint": "1",
          "name": "am",
          "cluster": "fakeCluster",
          "state": "",
          "startsAt": "0001-01-01T00:00:00Z",
          "source": "",
          "silencedBy": [
            "fakeSilence1",
            "fakeSilence2"
          ],
          "inhibitedBy": null
        }
      ],
      "receiver": "",
      "id": ""
    },
    {
      "annotations": [],
      "labels": {
        "instance": "3",
        "job": "blackbox"
      },
      "startsAt": "0001-01-01T00:00:00Z",
      "state": "suppressed",
      "alertmanager": [
        {
          "fingerprint": "1",
          "name": "am",
          "cluster": "fakeCluster",
          "state": "",
          "startsAt": "0001-01-01T00:00:00Z",
          "source": "",
          "silencedBy": [
            "fakeSilence1",
            "fakeSilence2"
          ],
          "inhibitedBy": null
        },
        {
          "fingerprint": "1",
          "name": "am",
          "cluster": "fakeCluster",
          "state": "",
          "startsAt": "0001-01-01T00:00:00Z",
          "source": "",
          "silencedBy": [
            "fakeSilence1",
            "fakeSilence2"
          ],
          "inhibitedBy": null
        }
      ],
      "receiver": "",
      "id": ""
    }
  ],
  "id": "",
  "alertmanagerCount": null,
  "stateCount": null,
  "shared": {
    "annotations": [
      {
        "name": "summary",
        "value": "this is summary",
        "visible": false,
        "isLink": false
      }
    ],
    "labels": {},
    "silences": {
      "fakeCluster": [
        "fakeSilence1",
        "fakeSilence2"
      ]
    }
  }
}`

	agJSON, _ := json.MarshalIndent(ag, "", "  ")
	if string(agJSON) != expectedJSON {
		diff := difflib.UnifiedDiff{
			A:        difflib.SplitLines(expectedJSON),
			B:        difflib.SplitLines(string(agJSON)),
			FromFile: "Expected",
			ToFile:   "Current",
			Context:  3,
		}
		text, err := difflib.GetUnifiedDiffString(diff)
		if err != nil {
			t.Error(err)
		}
		t.Errorf("JSON mismatch:\n%s", text)
	}
}

func TestDedupSharedMapsWithSingleAlert(t *testing.T) {
	ag := models.APIAlertGroup{
		AlertGroup: models.AlertGroup{
			Alerts: models.AlertList{
				models.Alert{},
			},
		},
	}
	ag.DedupSharedMaps()
}

func TestNameStatsSort(t *testing.T) {
	var nameStats = models.LabelNameStatsList{
		{
			Name: "@state",
			Hits: 24,
			Values: models.LabelValueStatsList{
				models.LabelValueStats{
					Value:   "suppressed",
					Raw:     "@state=suppressed",
					Hits:    8,
					Percent: 33,
					Offset:  67,
				},
				models.LabelValueStats{
					Value:   "active",
					Raw:     "@state=actuve",
					Hits:    16,
					Percent: 67,
					Offset:  0,
				},
			},
		},
		{
			Name: "cluster",
			Hits: 24,
			Values: models.LabelValueStatsList{
				models.LabelValueStats{
					Value:   "dev",
					Raw:     "cluster=dev",
					Hits:    10,
					Percent: 42,
					Offset:  0,
				},
				models.LabelValueStats{
					Value:   "prod",
					Raw:     "cluster=prod",
					Hits:    6,
					Percent: 25,
					Offset:  42,
				},
				models.LabelValueStats{
					Value:   "staging",
					Raw:     "cluster=staging",
					Hits:    8,
					Percent: 33,
					Offset:  67,
				},
			},
		},
		{
			Name: "alertname",
			Hits: 24,
			Values: models.LabelValueStatsList{
				models.LabelValueStats{
					Value:   "HTTP_Probe_Failed",
					Raw:     "alertname=HTTP_Probe_Failed",
					Hits:    4,
					Percent: 17,
					Offset:  0,
				},
				models.LabelValueStats{
					Value:   "Host_Down",
					Raw:     "alertname=Host_Down",
					Hits:    16,
					Percent: 67,
					Offset:  17,
				},
				models.LabelValueStats{
					Value: "Free_Disk_Space_Too_Low",
					Raw:   "alertname=Free_Disk_Space_Too_Low",

					Hits:    2,
					Percent: 8,
					Offset:  84,
				},
				models.LabelValueStats{
					Value:   "Memory_Usage_Too_High",
					Raw:     "alertname=Memory_Usage_Too_High",
					Hits:    2,
					Percent: 8,
					Offset:  92,
				},
			},
		},
		{
			Name: "instance",
			Hits: 24,
			Values: models.LabelValueStatsList{
				models.LabelValueStats{
					Value:   "server4",
					Raw:     "instance=server4",
					Hits:    2,
					Percent: 8,
				},
				models.LabelValueStats{
					Value:   "server5",
					Raw:     "instance=server5",
					Hits:    4,
					Percent: 17,
					Offset:  17,
				},
				models.LabelValueStats{
					Value:   "server6",
					Raw:     "instance=server6",
					Hits:    2,
					Percent: 8,
					Offset:  17,
				},
				models.LabelValueStats{
					Value:   "server1",
					Raw:     "instance=server1",
					Hits:    2,
					Percent: 8,
					Offset:  17,
				},
				models.LabelValueStats{
					Value:   "server2",
					Raw:     "instance=server2",
					Hits:    4,
					Percent: 17,
					Offset:  17,
				},
				models.LabelValueStats{
					Value:   "server3",
					Raw:     "instance=server3",
					Hits:    2,
					Percent: 8,
					Offset:  17,
				},
				models.LabelValueStats{
					Value:   "server7",
					Raw:     "instance=server7",
					Hits:    2,
					Percent: 8,
					Offset:  17,
				},
				models.LabelValueStats{
					Value:   "server8",
					Raw:     "instance=server8",
					Hits:    2,
					Percent: 8,
					Offset:  17,
				},
				models.LabelValueStats{
					Value:   "web1",
					Raw:     "instance=web1",
					Hits:    2,
					Percent: 8,
					Offset:  17,
				},
				models.LabelValueStats{
					Value:   "web2",
					Raw:     "instance=web2",
					Hits:    2,
					Percent: 8,
					Offset:  17,
				},
			},
		},
		{
			Name: "@receiver",
			Hits: 24,
			Values: models.LabelValueStatsList{
				models.LabelValueStats{
					Value:   "by-name",
					Raw:     "@receiver=by-name",
					Hits:    12,
					Percent: 50,
					Offset:  0,
				},
				models.LabelValueStats{
					Value:   "by-cluster-service",
					Raw:     "@receiver=by-cluster-service",
					Hits:    12,
					Percent: 50,
					Offset:  50,
				},
			},
		},
		{
			Name: "job",
			Hits: 16,
			Values: models.LabelValueStatsList{
				models.LabelValueStats{
					Value:   "node_exporter",
					Raw:     "job=node_exporter",
					Hits:    8,
					Percent: 50,
					Offset:  0,
				},
				models.LabelValueStats{
					Value:   "node_ping",
					Raw:     "job=node_ping",
					Hits:    8,
					Percent: 50,
					Offset:  50,
				},
			},
		},
	}

	b, err := json.Marshal(nameStats)
	if err != nil {
		t.Error(err)
	}
	before := string(b)

	for _, n := range nameStats {
		sort.Sort(n.Values)
	}
	sort.Sort(nameStats)

	a, err := json.Marshal(nameStats)
	if err != nil {
		t.Error(err)
	}
	after := string(a)

	if after == before {
		t.Errorf("Sorting LabelNameStatsList produces the same output as unsorted instance")
	}
}
