package server

import (
	"bytes"
	"context"
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/influxdata/httprouter"
	"github.com/influxdata/influxdb/v2/chronograf"
	"github.com/influxdata/influxdb/v2/chronograf/mocks"
)

func TestService_Queries(t *testing.T) {
	tests := []struct {
		name         string
		SourcesStore chronograf.SourcesStore
		ID           string
		w            *httptest.ResponseRecorder
		r            *http.Request
		want         string
	}{
		{
			name: "bad json",
			SourcesStore: &mocks.SourcesStore{
				GetF: func(ctx context.Context, ID int) (chronograf.Source, error) {
					return chronograf.Source{
						ID: ID,
					}, nil
				},
			},
			ID:   "1",
			w:    httptest.NewRecorder(),
			r:    httptest.NewRequest("POST", "/queries", bytes.NewReader([]byte(`howdy`))),
			want: `{"code":400,"message":"unparsable JSON"}`,
		},
		{
			name: "bad id",
			ID:   "howdy",
			w:    httptest.NewRecorder(),
			r:    httptest.NewRequest("POST", "/queries", bytes.NewReader([]byte{})),
			want: `{"code":422,"message":"error converting ID howdy"}`,
		},
		{
			name: "query with no template vars",
			SourcesStore: &mocks.SourcesStore{
				GetF: func(ctx context.Context, ID int) (chronograf.Source, error) {
					return chronograf.Source{
						ID: ID,
					}, nil
				},
			},
			ID: "1",
			w:  httptest.NewRecorder(),
			r: httptest.NewRequest("POST", "/queries", bytes.NewReader([]byte(`{
					"queries": [
					  {
						"query": "SELECT \"pingReq\" FROM db.\"monitor\".\"httpd\" WHERE time > now() - 1m",
						"id": "82b60d37-251e-4afe-ac93-ca20a3642b11"
					  }
					]}`))),
			want: `{"queries":[{"durationMs":59999,"id":"82b60d37-251e-4afe-ac93-ca20a3642b11","query":"SELECT \"pingReq\" FROM db.\"monitor\".\"httpd\" WHERE time \u003e now() - 1m","queryConfig":{"id":"82b60d37-251e-4afe-ac93-ca20a3642b11","database":"db","measurement":"httpd","retentionPolicy":"monitor","fields":[{"value":"pingReq","type":"field","alias":""}],"tags":{},"groupBy":{"time":"","tags":[]},"areTagsAccepted":false,"rawText":null,"range":{"upper":"","lower":"now() - 1m"},"shifts":[]},"queryAST":{"condition":{"expr":"binary","op":"\u003e","lhs":{"expr":"reference","val":"time"},"rhs":{"expr":"binary","op":"-","lhs":{"expr":"call","name":"now"},"rhs":{"expr":"literal","val":"1m","type":"duration"}}},"fields":[{"column":{"expr":"reference","val":"pingReq"}}],"sources":[{"database":"db","retentionPolicy":"monitor","name":"httpd","type":"measurement"}]}}]}
`,
		},
		{
			name: "query with unparsable query",
			SourcesStore: &mocks.SourcesStore{
				GetF: func(ctx context.Context, ID int) (chronograf.Source, error) {
					return chronograf.Source{
						ID: ID,
					}, nil
				},
			},
			ID: "1",
			w:  httptest.NewRecorder(),
			r: httptest.NewRequest("POST", "/queries", bytes.NewReader([]byte(`{
					"queries": [
					  {
						"query": "SHOW DATABASES",
						"id": "82b60d37-251e-4afe-ac93-ca20a3642b11"
					  }
					]}`))),
			want: `{"queries":[{"durationMs":0,"id":"82b60d37-251e-4afe-ac93-ca20a3642b11","query":"SHOW DATABASES","queryConfig":{"id":"82b60d37-251e-4afe-ac93-ca20a3642b11","database":"","measurement":"","retentionPolicy":"","fields":[],"tags":{},"groupBy":{"time":"","tags":[]},"areTagsAccepted":false,"rawText":"SHOW DATABASES","range":null,"shifts":[]}}]}
`,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			tt.r = tt.r.WithContext(context.WithValue(
				context.TODO(),
				httprouter.ParamsKey,
				httprouter.Params{
					{
						Key:   "id",
						Value: tt.ID,
					},
				}))
			s := &Service{
				Store: &mocks.Store{
					SourcesStore: tt.SourcesStore,
				},
				Logger: &mocks.TestLogger{},
			}
			s.Queries(tt.w, tt.r)
			got := tt.w.Body.String()
			if got != tt.want {
				t.Errorf("got:\n%s\nwant:\n%s\n", got, tt.want)
			}
		})
	}
}
