package gitlab

import (
	"net/http"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func TestListProjectFeatureFlags(t *testing.T) {
	t.Parallel()
	mux, client := setup(t)

	mux.HandleFunc("/api/v4/projects/333/feature_flags",
		func(w http.ResponseWriter, r *http.Request) {
			testMethod(t, r, http.MethodGet)
			mustWriteHTTPResponse(t, w, "testdata/list_project_feature_flags.json")
		})

	actual, _, err := client.ProjectFeatureFlags.ListProjectFeatureFlags(333, &ListProjectFeatureFlagOptions{})
	require.NoError(t, err)

	expected := []*ProjectFeatureFlag{
		{
			Name:        "merge_train",
			Description: "This feature is about merge train",
			Active:      true,
			Version:     "new_version_flag",
			CreatedAt:   Ptr(time.Date(2019, time.November, 4, 8, 13, 51, 0, time.UTC)),
			UpdatedAt:   Ptr(time.Date(2019, time.November, 4, 8, 13, 11, 0, time.UTC)),
			Scopes:      []*ProjectFeatureFlagScope{},
			Strategies: []*ProjectFeatureFlagStrategy{
				{
					ID:   1,
					Name: "userWithId",
					Parameters: &ProjectFeatureFlagStrategyParameter{
						UserIDs: "user1",
					},
					Scopes: []*ProjectFeatureFlagScope{
						{
							ID:               1,
							EnvironmentScope: "production",
						},
					},
				},
			},
		},
		{
			Name:        "new_live_trace",
			Description: "This is a new live trace feature",
			Active:      true,
			Version:     "new_version_flag",
			CreatedAt:   Ptr(time.Date(2019, time.November, 4, 8, 13, 10, 0, time.UTC)),
			UpdatedAt:   Ptr(time.Date(2019, time.November, 4, 8, 13, 10, 0, time.UTC)),
			Scopes:      []*ProjectFeatureFlagScope{},
			Strategies: []*ProjectFeatureFlagStrategy{
				{
					ID:         2,
					Name:       "default",
					Parameters: &ProjectFeatureFlagStrategyParameter{},
					Scopes: []*ProjectFeatureFlagScope{
						{
							ID:               2,
							EnvironmentScope: "staging",
						},
					},
				},
			},
		},
	}

	assert.Len(t, actual, len(expected))
	assert.Equal(t, expected, actual)
}

func TestGetProjectFeatureFlag(t *testing.T) {
	t.Parallel()
	mux, client := setup(t)

	mux.HandleFunc("/api/v4/projects/1/feature_flags/testing", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, http.MethodGet)
		mustWriteHTTPResponse(t, w, "testdata/get_project_feature_flag.json")
	})

	actual, resp, err := client.ProjectFeatureFlags.GetProjectFeatureFlag(1, "testing")
	require.NoError(t, err)
	require.NotNil(t, resp)

	expected := &ProjectFeatureFlag{
		Name:      "awesome_feature",
		Active:    true,
		Version:   "new_version_flag",
		CreatedAt: Ptr(time.Date(2020, time.May, 13, 19, 56, 33, 0, time.UTC)),
		UpdatedAt: Ptr(time.Date(2020, time.May, 13, 19, 56, 33, 0, time.UTC)),
		Scopes:    []*ProjectFeatureFlagScope{},
		Strategies: []*ProjectFeatureFlagStrategy{
			{
				ID:         36,
				Name:       "default",
				Parameters: &ProjectFeatureFlagStrategyParameter{},
				Scopes: []*ProjectFeatureFlagScope{
					{
						ID:               37,
						EnvironmentScope: "production",
					},
				},
			},
			{
				ID:   24,
				Name: "flexibleRollout",
				Parameters: &ProjectFeatureFlagStrategyParameter{
					GroupID:    "default",
					Rollout:    "50",
					Stickiness: "default",
				},
				Scopes: []*ProjectFeatureFlagScope{
					{
						ID:               52,
						EnvironmentScope: "*",
					},
				},
			},
		},
	}

	assert.Equal(t, expected, actual)
}

func TestCreateProjectFeatureFlag(t *testing.T) {
	t.Parallel()
	mux, client := setup(t)

	mux.HandleFunc("/api/v4/projects/1/feature_flags/testing", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, http.MethodPut)
		mustWriteHTTPResponse(t, w, "testdata/create_project_feature_flag.json")
	})

	actual, _, err := client.ProjectFeatureFlags.UpdateProjectFeatureFlag(1, "testing", &UpdateProjectFeatureFlagOptions{})
	require.NoError(t, err)

	expected := &ProjectFeatureFlag{
		Name:      "awesome_feature",
		Active:    true,
		Version:   "new_version_flag",
		CreatedAt: Ptr(time.Date(2020, time.May, 13, 19, 56, 33, 0, time.UTC)),
		UpdatedAt: Ptr(time.Date(2020, time.May, 13, 19, 56, 33, 0, time.UTC)),
		Scopes:    []*ProjectFeatureFlagScope{},
		Strategies: []*ProjectFeatureFlagStrategy{
			{
				ID:         36,
				Name:       "default",
				Parameters: &ProjectFeatureFlagStrategyParameter{},
				Scopes: []*ProjectFeatureFlagScope{
					{
						ID:               37,
						EnvironmentScope: "production",
					},
				},
			},
		},
	}

	assert.Equal(t, expected, actual)
}

func TestUpdateProjectFeatureFlag(t *testing.T) {
	t.Parallel()
	mux, client := setup(t)

	mux.HandleFunc("/api/v4/projects/1/feature_flags/testing", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, http.MethodPut)
		mustWriteHTTPResponse(t, w, "testdata/update_project_feature_flag.json")
	})

	actual, _, err := client.ProjectFeatureFlags.UpdateProjectFeatureFlag(1, "testing", &UpdateProjectFeatureFlagOptions{})
	require.NoError(t, err)

	expected := &ProjectFeatureFlag{
		Name:      "awesome_feature",
		Active:    true,
		Version:   "new_version_flag",
		CreatedAt: Ptr(time.Date(2020, time.May, 13, 20, 10, 32, 0, time.UTC)),
		UpdatedAt: Ptr(time.Date(2020, time.May, 13, 20, 10, 32, 0, time.UTC)),
		Scopes:    []*ProjectFeatureFlagScope{},
		Strategies: []*ProjectFeatureFlagStrategy{
			{
				ID:   38,
				Name: "gradualRolloutUserId",
				Parameters: &ProjectFeatureFlagStrategyParameter{
					GroupID:    "default",
					Percentage: "25",
				},
				Scopes: []*ProjectFeatureFlagScope{
					{
						ID:               40,
						EnvironmentScope: "staging",
					},
				},
			},
			{
				ID:         37,
				Name:       "default",
				Parameters: &ProjectFeatureFlagStrategyParameter{},
				Scopes: []*ProjectFeatureFlagScope{
					{
						ID:               39,
						EnvironmentScope: "production",
					},
				},
			},
		},
	}

	assert.Equal(t, expected, actual)
}

func TestDeleteProjectFeatureFlag(t *testing.T) {
	t.Parallel()
	mux, client := setup(t)

	mux.HandleFunc("/api/v4/projects/1/feature_flags/testing", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, http.MethodDelete)
	})

	_, err := client.ProjectFeatureFlags.DeleteProjectFeatureFlag(1, "testing")
	require.NoError(t, err)
}
