// Copyright 2020 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package integration_test

import (
	"log"
	"net/url"
	"testing"

	gitea "gitea.dev/sdk"

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

func TestMyUser(t *testing.T) {
	log.Println("== TestMyUser ==")
	c := newTestClient()
	user, _, err := c.Users.GetMyUserInfo(t.Context())
	assert.NoError(t, err)

	assert.EqualValues(t, 2, user.ID)
	assert.EqualValues(t, getGiteaUsername(), user.UserName)
	assert.EqualValues(t, testEmailAddress(getGiteaUsername()), user.Email)
	assert.EqualValues(t, "", user.FullName)
	assert.EqualValues(t, "/avatars/5b62046451cec0c41bb313e71571068e", urlRequestURI(t, user.AvatarURL))
	assert.True(t, user.IsAdmin)
}

func urlRequestURI(t *testing.T, rawURL string) string {
	t.Helper()
	parsedURL, err := url.Parse(rawURL)
	assert.NoError(t, err)
	return parsedURL.RequestURI()
}

func TestUserApp(t *testing.T) {
	log.Println("== TestUserApp ==")
	c := newTestClient()

	result, _, err := c.Users.ListAccessTokens(t.Context(), gitea.ListAccessTokensOptions{})
	assert.NoError(t, err)
	assert.Len(t, result, 1)
	assert.EqualValues(t, "gitea-admin", result[0].Name)

	t1, _, err := c.Users.CreateAccessToken(t.Context(), gitea.CreateAccessTokenOption{Name: "TestCreateAccessToken", Scopes: []gitea.AccessTokenScope{gitea.AccessTokenScopeAll}})
	assert.NoError(t, err)
	assert.EqualValues(t, "TestCreateAccessToken", t1.Name)
	result, _, _ = c.Users.ListAccessTokens(t.Context(), gitea.ListAccessTokensOptions{})
	assert.Len(t, result, 2)

	_, err = c.Users.DeleteAccessToken(t.Context(), t1.ID)
	assert.NoError(t, err)
	result, _, _ = c.Users.ListAccessTokens(t.Context(), gitea.ListAccessTokensOptions{})
	assert.Len(t, result, 1)
}

func TestUserSearch(t *testing.T) {
	log.Println("== TestUserSearch ==")
	c := newTestClient()

	createTestUser(t, "sdksearchalpha", c)
	createTestUser(t, "sdksearchbeta", c)
	createTestUser(t, "sdksearchgamma", c)
	createTestUser(t, "sdksearchdelta", c)
	createTestUser(t, "sdksearchepsilon", c)
	createTestUser(t, "sdksearchother", c)

	ul, _, err := c.Users.SearchUsers(t.Context(), gitea.SearchUsersOption{KeyWord: "sdksearchother"})
	assert.NoError(t, err)
	assert.Len(t, ul, 1)

	ul, _, err = c.Users.SearchUsers(t.Context(), gitea.SearchUsersOption{KeyWord: "sdksearchabsent"})
	assert.NoError(t, err)
	assert.Len(t, ul, 0)

	ul, _, err = c.Users.SearchUsers(t.Context(), gitea.SearchUsersOption{KeyWord: "sdksearch"})
	assert.NoError(t, err)
	assert.Len(t, ul, 6)
}

func TestUserFollow(t *testing.T) {
	log.Println("== TestUserFollow ==")
	c := newTestClient()
	me, _, _ := c.Users.GetMyUserInfo(t.Context())

	uA := "uFollow_A"
	uB := "uFollow_B"
	uC := "uFollow_C"
	createTestUser(t, uA, c)
	createTestUser(t, uB, c)
	createTestUser(t, uC, c)

	// A follow ME
	// B follow C & ME
	// C follow A & B & ME
	c.SetSudo(uA)
	_, err := c.Users.Follow(t.Context(), me.UserName)
	assert.NoError(t, err)
	c.SetSudo(uB)
	_, err = c.Users.Follow(t.Context(), me.UserName)
	assert.NoError(t, err)
	_, err = c.Users.Follow(t.Context(), uC)
	assert.NoError(t, err)
	c.SetSudo(uC)
	_, err = c.Users.Follow(t.Context(), me.UserName)
	assert.NoError(t, err)
	_, err = c.Users.Follow(t.Context(), uA)
	assert.NoError(t, err)
	_, err = c.Users.Follow(t.Context(), uB)
	assert.NoError(t, err)

	// C unfollow me
	_, err = c.Users.Unfollow(t.Context(), me.UserName)
	assert.NoError(t, err)

	// ListMyFollowers of me
	c.SetSudo("")
	f, _, err := c.Users.ListMyFollowers(t.Context(), gitea.ListFollowersOptions{})
	assert.NoError(t, err)
	assert.Len(t, f, 2)

	// ListFollowers of A
	f, _, err = c.Users.ListFollowers(t.Context(), uA, gitea.ListFollowersOptions{})
	assert.NoError(t, err)
	assert.Len(t, f, 1)

	// ListMyFollowing of me
	f, _, err = c.Users.ListMyFollowing(t.Context(), gitea.ListFollowingOptions{})
	assert.NoError(t, err)
	assert.Len(t, f, 0)

	// ListFollowing of A
	f, _, err = c.Users.ListFollowing(t.Context(), uA, gitea.ListFollowingOptions{})
	assert.NoError(t, err)
	assert.Len(t, f, 1)
	assert.EqualValues(t, me.ID, f[0].ID)

	isFollow, _ := c.Users.IsFollowing(t.Context(), uA)
	assert.False(t, isFollow)
	isFollow, _ = c.Users.IsUserFollowing(t.Context(), uB, uC)
	assert.True(t, isFollow)
}

func TestUserEmail(t *testing.T) {
	log.Println("== TestUserEmail ==")
	c := newTestClient()
	userN := "TestUserEmail"
	createTestUser(t, userN, c)
	c.SetSudo(userN)

	// ListEmails
	el, _, err := c.Users.ListEmails(t.Context(), gitea.ListEmailsOptions{})
	assert.NoError(t, err)
	assert.Len(t, el, 1)
	assert.EqualValues(t, testEmailAddress("TestUserEmail"), el[0].Email)
	assert.True(t, el[0].Primary)

	// AddEmail
	mails := []string{testEmailAddress("wow"), testEmailAddress("speed")}
	el, _, err = c.Users.AddEmail(t.Context(), gitea.CreateEmailOption{Emails: mails})
	assert.NoError(t, err)
	assert.Len(t, el, 3)
	_, _, err = c.Users.AddEmail(t.Context(), gitea.CreateEmailOption{Emails: []string{mails[1]}})
	assert.Error(t, err)
	el, _, err = c.Users.ListEmails(t.Context(), gitea.ListEmailsOptions{})
	assert.NoError(t, err)
	assert.Len(t, el, 3)

	// DeleteEmail
	_, err = c.Users.DeleteEmail(t.Context(), gitea.DeleteEmailOption{Emails: []string{mails[1]}})
	assert.NoError(t, err)
	_, err = c.Users.DeleteEmail(t.Context(), gitea.DeleteEmailOption{Emails: []string{testEmailAddress("imaginary")}})
	assert.Error(t, err)

	el, _, err = c.Users.ListEmails(t.Context(), gitea.ListEmailsOptions{})
	assert.NoError(t, err)
	assert.Len(t, el, 2)
	_, err = c.Users.DeleteEmail(t.Context(), gitea.DeleteEmailOption{Emails: []string{mails[0]}})
	assert.NoError(t, err)
}

func TestGetUserByID(t *testing.T) {
	log.Println("== TestGetUserByID ==")
	c := newTestClient()

	user1 := createTestUser(t, "user1", c)
	user2 := createTestUser(t, "user2", c)

	r1, _, err := c.Users.GetUserByID(t.Context(), user1.ID)
	assert.NoError(t, err)
	assert.NotNil(t, r1)
	assert.Equal(t, user1.UserName, r1.UserName)

	r2, _, err := c.Users.GetUserByID(t.Context(), user2.ID)
	assert.NoError(t, err)
	assert.NotNil(t, r2)
	assert.Equal(t, user2.UserName, r2.UserName)

	r3, _, err := c.Users.GetUserByID(t.Context(), 999999)
	assert.Error(t, err)
	assert.Nil(t, r3)

	r4, _, err := c.Users.GetUserByID(t.Context(), -1)
	assert.Error(t, err)
	assert.Nil(t, r4)
}

// userToStringSlice return string slice based on UserName of users
func userToStringSlice(users []*gitea.User) []string {
	result := make([]string, 0, len(users))
	for i := range users {
		result = append(result, users[i].UserName)
	}
	return result
}
