package server_test

import (
	"context"
	"encoding/json"
	"net/http/httptest"
	"net/url"
	"strings"
	"testing"

	"github.com/google/go-cmp/cmp"
	"github.com/influxdata/influxdb/v2/chronograf"
	"github.com/influxdata/influxdb/v2/chronograf/mocks"
	"github.com/influxdata/influxdb/v2/chronograf/server"
)

func Test_Layouts(t *testing.T) {
	layoutTests := []struct {
		name       string
		expected   chronograf.Layout
		allLayouts []chronograf.Layout
		focusedApp string // should filter all layouts to this app only
		shouldErr  bool
	}{
		{
			"empty layout",
			chronograf.Layout{},
			[]chronograf.Layout{},
			"",
			false,
		},
		{
			"several layouts",
			chronograf.Layout{
				ID:          "d20a21c8-69f1-4780-90fe-e69f5e4d138c",
				Application: "influxdb",
				Measurement: "influxdb",
			},
			[]chronograf.Layout{
				chronograf.Layout{
					ID:          "d20a21c8-69f1-4780-90fe-e69f5e4d138c",
					Application: "influxdb",
					Measurement: "influxdb",
				},
			},
			"",
			false,
		},
		{
			"filtered app",
			chronograf.Layout{
				ID:          "d20a21c8-69f1-4780-90fe-e69f5e4d138c",
				Application: "influxdb",
				Measurement: "influxdb",
			},
			[]chronograf.Layout{
				chronograf.Layout{
					ID:          "d20a21c8-69f1-4780-90fe-e69f5e4d138c",
					Application: "influxdb",
					Measurement: "influxdb",
				},
				chronograf.Layout{
					ID:          "b020101b-ea6b-4c8c-9f0e-db0ba501f4ef",
					Application: "chronograf",
					Measurement: "chronograf",
				},
			},
			"influxdb",
			false,
		},
		{
			"axis zero values",
			chronograf.Layout{
				ID:          "d20a21c8-69f1-4780-90fe-e69f5e4d138c",
				Application: "influxdb",
				Measurement: "influxdb",
				Cells: []chronograf.Cell{
					{
						X:          0,
						Y:          0,
						W:          4,
						H:          4,
						I:          "3b0e646b-2ca3-4df2-95a5-fd80915459dd",
						Name:       "A Graph",
						CellColors: []chronograf.CellColor{},
						Axes: map[string]chronograf.Axis{
							"x": chronograf.Axis{
								Bounds: []string{},
							},
							"y": chronograf.Axis{
								Bounds: []string{},
							},
							"y2": chronograf.Axis{
								Bounds: []string{},
							},
						},
					},
				},
			},
			[]chronograf.Layout{
				chronograf.Layout{
					ID:          "d20a21c8-69f1-4780-90fe-e69f5e4d138c",
					Application: "influxdb",
					Measurement: "influxdb",
					Cells: []chronograf.Cell{
						{
							X:          0,
							Y:          0,
							W:          4,
							H:          4,
							I:          "3b0e646b-2ca3-4df2-95a5-fd80915459dd",
							CellColors: []chronograf.CellColor{},
							Name:       "A Graph",
						},
					},
				},
			},
			"",
			false,
		},
	}

	for _, test := range layoutTests {
		test := test
		t.Run(test.name, func(t *testing.T) {
			t.Parallel()

			// setup mock chronograf.Service and mock logger
			lg := &mocks.TestLogger{}
			svc := server.Service{
				Store: &mocks.Store{LayoutsStore: &mocks.LayoutsStore{
					AllF: func(ctx context.Context) ([]chronograf.Layout, error) {
						if len(test.allLayouts) == 0 {
							return []chronograf.Layout{
								test.expected,
							}, nil
						} else {
							return test.allLayouts, nil
						}
					},
				},
				},
				Logger: lg,
			}

			// setup mock request and response
			rr := httptest.NewRecorder()
			reqURL := url.URL{
				Path: "/chronograf/v1/layouts",
			}
			params := reqURL.Query()

			// add query params required by test
			if test.focusedApp != "" {
				params.Add("app", test.focusedApp)
			}

			// re-inject query params
			reqURL.RawQuery = params.Encode()

			req := httptest.NewRequest("GET", reqURL.RequestURI(), strings.NewReader(""))

			// invoke handler for layouts endpoint
			svc.Layouts(rr, req)

			// create a throwaway frame to unwrap Layouts
			respFrame := struct {
				Layouts []struct {
					chronograf.Layout
					Link interface{} `json:"-"`
				} `json:"layouts"`
			}{}

			// decode resp into respFrame
			resp := rr.Result()
			if err := json.NewDecoder(resp.Body).Decode(&respFrame); err != nil {
				t.Fatalf("%q - Error unmarshaling JSON: err: %s", test.name, err.Error())
			}

			// compare actual and expected
			if !cmp.Equal(test.expected, respFrame.Layouts[0].Layout) {
				t.Fatalf("%q - Expected layouts to be equal: diff:\n\t%s", test.name, cmp.Diff(test.expected, respFrame.Layouts[0].Layout))
			}
		})
	}
}
