package gitlab

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

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

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

	mux.HandleFunc("/api/v4/hooks", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, http.MethodGet)
		fmt.Fprint(w, `
		[
			{
			  "id":1,
			  "url":"https://gitlab.example.com/hook",
			  "name":"Test Hook",
			  "description":"A test hook",
			  "created_at":"2016-10-31T12:32:15.192Z",
			  "push_events":true,
			  "tag_push_events":false,
			  "merge_requests_events": true,
			  "repository_update_events": true,
			  "enable_ssl_verification":true,
			  "url_variables":[{"key":"abc","value":"def"}]
			}
		]`)
	})

	hooks, _, err := client.SystemHooks.ListHooks()
	require.NoError(t, err)

	createdAt := time.Date(2016, time.October, 31, 12, 32, 15, 192000000, time.UTC)
	want := []*Hook{{
		ID:                     1,
		URL:                    "https://gitlab.example.com/hook",
		Name:                   "Test Hook",
		Description:            "A test hook",
		CreatedAt:              &createdAt,
		PushEvents:             true,
		TagPushEvents:          false,
		MergeRequestsEvents:    true,
		RepositoryUpdateEvents: true,
		EnableSSLVerification:  true,
		URLVariables:           []HookURLVariable{{Key: "abc", Value: "def"}},
	}}
	require.Equal(t, want, hooks)
}

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

	mux.HandleFunc("/api/v4/hooks/1", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, http.MethodGet)
		fmt.Fprint(w, `
		{
			"id":1,
			"url":"https://gitlab.example.com/hook",
			"name":"Test Hook",
			"description":"A test hook",
			"created_at":"2016-10-31T12:32:15.192Z",
			"push_events":true,
			"tag_push_events":false,
			"merge_requests_events": true,
			"repository_update_events": true,
			"enable_ssl_verification":true,
			"url_variables":[{"key":"abc","value":"def"}]
		}`)
	})

	hooks, _, err := client.SystemHooks.GetHook(1)
	require.NoError(t, err)

	createdAt := time.Date(2016, time.October, 31, 12, 32, 15, 192000000, time.UTC)
	want := &Hook{
		ID:                     1,
		URL:                    "https://gitlab.example.com/hook",
		Name:                   "Test Hook",
		Description:            "A test hook",
		CreatedAt:              &createdAt,
		PushEvents:             true,
		TagPushEvents:          false,
		MergeRequestsEvents:    true,
		RepositoryUpdateEvents: true,
		EnableSSLVerification:  true,
		URLVariables:           []HookURLVariable{{Key: "abc", Value: "def"}},
	}
	require.Equal(t, want, hooks)
}

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

	mux.HandleFunc("/api/v4/hooks", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, http.MethodPost)
		fmt.Fprint(w, `{
			"id": 1,
			"url": "https://gitlab.example.com/hook",
			"name": "Test Hook",
			"description": "A test hook",
			"url_variables": [{"key": "abc", "value": "def"}]
		}`)
	})

	opt := &AddHookOptions{
		URL:         Ptr("https://gitlab.example.com/hook"),
		Name:        Ptr("Test Hook"),
		Description: Ptr("A test hook"),
	}

	hook, _, err := client.SystemHooks.AddHook(opt)
	require.NoError(t, err)

	want := &Hook{
		ID:           1,
		URL:          "https://gitlab.example.com/hook",
		Name:         "Test Hook",
		Description:  "A test hook",
		URLVariables: []HookURLVariable{{Key: "abc", Value: "def"}},
	}
	require.Equal(t, want, hook)
}

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

	mux.HandleFunc("/api/v4/hooks/1", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, http.MethodPut)
		fmt.Fprint(w, `{
			"id": 1,
			"url": "https://gitlab.example.com/hook",
			"name": "Test Hook",
			"description": "An updated test hook",
			"token_present": true,
			"signing_token_present": true,
			"url_variables": [{"key": "abc", "value": "def"}]
		}`)
	})

	opt := &EditHookOptions{
		URL:          Ptr("https://gitlab.example.com/hook"),
		Name:         Ptr("Test Hook"),
		Description:  Ptr("An updated test hook"),
		Token:        Ptr("supersecret"),
		SigningToken: Ptr("whsec_abc"),
	}

	hook, _, err := client.SystemHooks.EditHook(1, opt)
	require.NoError(t, err)

	want := &Hook{
		ID:                  1,
		URL:                 "https://gitlab.example.com/hook",
		Name:                "Test Hook",
		Description:         "An updated test hook",
		TokenPresent:        true,
		SigningTokenPresent: true,
		URLVariables:        []HookURLVariable{{Key: "abc", Value: "def"}},
	}
	require.Equal(t, want, hook)
}

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

	mux.HandleFunc("/api/v4/hooks/1", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, http.MethodPost)
		fmt.Fprint(w, `{"project_id" : 1,"owner_email" : "example@gitlabhq.com","owner_name" : "Someone",
				"name" : "Ruby","path" : "ruby","event_name" : "project_create"}`)
	})

	hook, _, err := client.SystemHooks.TestHook(1)
	require.NoError(t, err)

	want := &HookEvent{
		EventName:  "project_create",
		Name:       "Ruby",
		Path:       "ruby",
		ProjectID:  1,
		OwnerName:  "Someone",
		OwnerEmail: "example@gitlabhq.com",
	}
	require.Equal(t, want, hook)
}

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

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

	_, err := client.SystemHooks.DeleteHook(1)
	require.NoError(t, err)
}

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

	mux.HandleFunc("/api/v4/hooks/1/url_variables/abc", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, http.MethodPut)
		w.WriteHeader(http.StatusCreated)
	})

	_, err := client.SystemHooks.SetHookURLVariable(1, "abc", &SetHookURLVariableOptions{
		Value: Ptr("def"),
	})
	require.NoError(t, err)
}

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

	mux.HandleFunc("/api/v4/hooks/1/url_variables/abc", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, http.MethodDelete)
	})

	_, err := client.SystemHooks.DeleteHookURLVariable(1, "abc")
	require.NoError(t, err)
}
