package metricstui

import (
	"strings"
	"testing"
)

func TestDecodeQueryRangeResponseMultiSeries(t *testing.T) {
	t.Parallel()

	raw := []byte(`{
		"status":"success",
		"data":{
			"resultType":"matrix",
			"result":[
				{
					"metric":{"job":"api","instance":"b","__name__":"http_requests_total"},
					"values":[
						[1712123000,"1.25"],
						[1712123060,"2.5"]
					]
				},
				{
					"metric":{"instance":"a","__name__":"http_requests_total","job":"api"},
					"values":[
						[1712123000,"3.5"]
					]
				}
			]
		}
	}`)

	got, err := DecodeQueryRangeResponse(raw)
	if err != nil {
		t.Fatalf("DecodeQueryRangeResponse() error = %v", err)
	}

	if got, want := len(got.Series), 2; got != want {
		t.Fatalf("series count = %d, want %d", got, want)
	}

	if got, want := got.Series[0].Label, `http_requests_total{instance="a",job="api"}`; got != want {
		t.Fatalf("series[0].label = %q, want %q", got, want)
	}
	if got, want := got.Series[1].Label, `http_requests_total{instance="b",job="api"}`; got != want {
		t.Fatalf("series[1].label = %q, want %q", got, want)
	}

	if got, want := len(got.Series[0].Samples), 1; got != want {
		t.Fatalf("series[0].samples = %d, want %d", got, want)
	}
	if got, want := got.Series[0].Samples[0].Value, 3.5; got != want {
		t.Fatalf("series[0].sample[0].value = %v, want %v", got, want)
	}

	if got, want := len(got.Series[1].Samples), 2; got != want {
		t.Fatalf("series[1].samples = %d, want %d", got, want)
	}
	if got, want := got.Series[1].Samples[0].Value, 1.25; got != want {
		t.Fatalf("series[1].sample[0].value = %v, want %v", got, want)
	}
	if got, want := got.Series[1].Samples[1].Value, 2.5; got != want {
		t.Fatalf("series[1].sample[1].value = %v, want %v", got, want)
	}
}

func TestDecodeQueryRangeResponseEmptyResult(t *testing.T) {
	t.Parallel()

	raw := []byte(`{"status":"success","data":{"resultType":"matrix","result":[]}}`)

	got, err := DecodeQueryRangeResponse(raw)
	if err != nil {
		t.Fatalf("DecodeQueryRangeResponse() error = %v", err)
	}

	if got, want := len(got.Series), 0; got != want {
		t.Fatalf("series count = %d, want %d", got, want)
	}
}

func TestDecodeQueryRangeResponseMalformedJSON(t *testing.T) {
	t.Parallel()

	_, err := DecodeQueryRangeResponse([]byte(`{"status":"success","data":`))
	if err == nil {
		t.Fatal("DecodeQueryRangeResponse() error = nil, want decode error")
	}
	if got := err.Error(); !strings.Contains(got, "decode prometheus query_range response") {
		t.Fatalf("error = %q, want decode prefix", got)
	}
}

func TestDecodeQueryRangeResponseRejectsNonMatrixResultType(t *testing.T) {
	t.Parallel()

	raw := []byte(`{"status":"success","data":{"resultType":"vector","result":[]}}`)

	_, err := DecodeQueryRangeResponse(raw)
	if err == nil {
		t.Fatal("DecodeQueryRangeResponse() error = nil, want validation error")
	}
	if got, want := err.Error(), "unexpected prometheus query_range result type: vector"; got != want {
		t.Fatalf("error = %q, want %q", got, want)
	}
}

func TestDecodeQueryRangeResponseReportsAPIPayloadErrors(t *testing.T) {
	t.Parallel()

	raw := []byte(`{
		"status":"error",
		"errorType":"bad_data",
		"error":"parse error at char 3",
		"data":{"resultType":"matrix","result":[]}
	}`)

	_, err := DecodeQueryRangeResponse(raw)
	if err == nil {
		t.Fatal("DecodeQueryRangeResponse() error = nil, want API error")
	}
	if got, want := err.Error(), "prometheus query_range api error: bad_data: parse error at char 3"; got != want {
		t.Fatalf("error = %q, want %q", got, want)
	}
}

func TestDecodeQueryRangeResponseSkipsInvalidNumericSamplesAndCountsThem(t *testing.T) {
	t.Parallel()

	raw := []byte(`{
		"status":"success",
		"data":{
			"resultType":"matrix",
			"result":[
				{
					"metric":{"__name__":"cpu_usage","instance":"a"},
					"values":[
						[1712123000,"1.25"],
						[1712123060,"not-a-number"],
						[1712123120,"3.75"]
					]
				}
			]
		}
	}`)

	got, err := DecodeQueryRangeResponse(raw)
	if err != nil {
		t.Fatalf("DecodeQueryRangeResponse() error = %v", err)
	}

	if got, want := len(got.Series), 1; got != want {
		t.Fatalf("series count = %d, want %d", got, want)
	}
	if got, want := got.Series[0].Label, `cpu_usage{instance="a"}`; got != want {
		t.Fatalf("series[0].label = %q, want %q", got, want)
	}
	if got, want := len(got.Series[0].Samples), 2; got != want {
		t.Fatalf("series[0].samples = %d, want %d", got, want)
	}
	if got, want := got.Series[0].InvalidSamples, 1; got != want {
		t.Fatalf("series[0].invalid_samples = %d, want %d", got, want)
	}
}
