package integration

import (
	"fmt"
	"testing"

	"github.com/contiamo/dev/tests/integration/suite"
)

type Payload suite.Payload

func TestDataSourceListing(t *testing.T) {
	s := suite.New(t)
	createFieldSpec(s)
	createDataSources(s)

	s.Run("it should work to list datasources without filters", func(s *suite.Suite) {
		path := fmt.Sprintf("/hub/api/v1/%s/datasources", s.ProjectID)
		resp := s.Get(path)
		defer resp.Body.Close()
		payload := s.ParsePayload(resp.Body)
		hits := s.Jq(payload, `.data | sort | .[] | select(.name == "ds1" or .name == "ds2" or .name == "ds3") | .name`)
		s.Require().Len(hits, 3)
		s.Require().Equal(hits[0], "ds1")
		s.Require().Equal(hits[1], "ds2")
		s.Require().Equal(hits[2], "ds3")
	})

	s.Run("it should work to filter datasources by name", func(s *suite.Suite) {
		path := fmt.Sprintf("/hub/api/v1/%s/datasources", s.ProjectID)
		filter := Payload{
			"filters": []Payload{
				{
					"property":  "name",
					"operation": "eq",
					"value":     "ds1",
				},
			},
		}
		path = fmt.Sprintf("%v?filter=%v", path, s.URLEncode(filter))
		resp := s.Get(path)
		defer resp.Body.Close()
		payload := s.ParsePayload(resp.Body)
		hits := s.Jq(payload, `.data[].name`)
		s.Require().Len(hits, 1)
		s.Require().Equal(hits[0], "ds1")
	})

	s.Run("it should work to filter datasources by custom properties", func(s *suite.Suite) {
		s.Skip("Broken. Must be fixed")
		path := fmt.Sprintf("/hub/api/v1/%s/datasources", s.ProjectID)
		filter := Payload{
			"filters": []Payload{
				{
					"property":  "custom1",
					"operation": "eq",
					"value":     "custom text in ds1",
				},
			},
		}
		path = fmt.Sprintf("%v?filter=%v", path, s.URLEncode(filter))
		resp := s.Get(path)
		defer resp.Body.Close()
		payload := s.ParsePayload(resp.Body)
		hits := s.Jq(payload, `.data[].name`)
		s.Require().Len(hits, 1)
		s.Require().Equal(hits[0], "ds1")
	})

	s.Run("it should work to filter datasources by custom properties using the 'in' operator", func(s *suite.Suite) {
		path := fmt.Sprintf("/hub/api/v1/%s/datasources", s.ProjectID)
		filter := Payload{
			"filters": []Payload{
				{
					"property":  "custom1",
					"operation": "in",
					"value": []string{
						"custom text in ds1",
						"custom text in ds2",
					},
				},
			},
		}
		path = fmt.Sprintf("%v?filter=%v", path, s.URLEncode(filter))
		resp := s.Get(path)
		defer resp.Body.Close()
		payload := s.ParsePayload(resp.Body)
		hits := s.Jq(payload, `.data | sort | .[].name`)
		s.Require().Len(hits, 2)
		s.Require().Equal(hits[0], "ds1")
		s.Require().Equal(hits[1], "ds2")
	})
}

func createFieldSpec(s *suite.Suite) {
	path := fmt.Sprintf("/hub/api/v1/%s/fields/datasource", s.ProjectID)
	resp := s.Get(path)
	defer resp.Body.Close()
	payload := s.ParsePayload(resp.Body)
	fields, ok := payload["fields"].([]interface{})
	s.Assert().True(ok)
	fields = append(fields, map[string]interface{}{
		"name": "custom1",
		"type": "text",
		"kind": "custom",
	})
	fields = append(fields, map[string]interface{}{
		"name": "custom2",
		"type": "select",
		"kind": "custom",
		"validValues": []string{
			"foo",
			"bar",
			"baz",
		},
	})
	payload["fields"] = fields
	s.Put(path, payload)
}

func createDataSources(s *suite.Suite) {
	path := fmt.Sprintf("/hub/api/v1/%s/datasources", s.ProjectID)
	payload := Payload{
		"name": "ds1",
		"type": "virtual",
	}
	s.Post(path, payload)
	payload = Payload{
		"name": "ds2",
		"type": "virtual",
	}
	s.Post(path, payload)
	payload = Payload{
		"name": "ds3",
		"type": "virtual",
	}
	s.Post(path, payload)

	path = fmt.Sprintf("/hub/api/v1/%s/datasources/ds1", s.ProjectID)
	payload = Payload{
		"props": Payload{
			"custom1": "custom text in ds1",
			"custom2": "foo",
		},
	}
	s.Patch(path, payload)

	path = fmt.Sprintf("/hub/api/v1/%s/datasources/ds2", s.ProjectID)
	payload = Payload{
		"props": Payload{
			"custom1": "custom text in ds2",
			"custom2": "bar",
		},
	}
	s.Patch(path, payload)

	path = fmt.Sprintf("/hub/api/v1/%s/datasources/ds3", s.ProjectID)
	payload = Payload{
		"props": Payload{
			"custom1": "custom text in ds3",
			"custom2": "bar",
		},
	}
	s.Patch(path, payload)
}
