// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT

package user_test

import (
	"testing"

	"code.gitea.io/gitea/models/unittest"
	user_model "code.gitea.io/gitea/models/user"
	"code.gitea.io/gitea/modules/setting"
	"code.gitea.io/gitea/modules/test"

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

func TestAccountRequestValidationCode(t *testing.T) {
	require.NoError(t, unittest.PrepareTestDatabase())
	defer test.MockVariableValue(&setting.Service.RegisterManualConfirm, true)()

	user := &user_model.User{
		Name:   "account-request-code-user",
		Email:  "account-request-code-user@example.com",
		Passwd: "password",
	}
	require.NoError(t, user_model.CreateUser(t.Context(), user, &user_model.Meta{}))
	require.NoError(t, user_model.ResetAccountRequestToPendingEmailValidation(t.Context(), user))

	code := user_model.GenerateAccountRequestValidationCode(user)
	verifiedUser := user_model.VerifyAccountRequestValidationCode(t.Context(), code)
	require.NotNil(t, verifiedUser)
	require.Equal(t, user.ID, verifiedUser.ID)
}

func TestAccountRequestValidationCodeStoredFallback(t *testing.T) {
	require.NoError(t, unittest.PrepareTestDatabase())
	defer test.MockVariableValue(&setting.Service.RegisterManualConfirm, true)()

	user := &user_model.User{
		Name:   "account-request-stored-code-user",
		Email:  "account-request-stored-code-user@example.com",
		Passwd: "password",
	}
	require.NoError(t, user_model.CreateUser(t.Context(), user, &user_model.Meta{}))
	require.NoError(t, user_model.ResetAccountRequestToPendingEmailValidation(t.Context(), user))

	code := user_model.GenerateAccountRequestValidationCode(user)
	require.NoError(t, user_model.SetAccountRequestValidationCode(t.Context(), user.ID, code))

	user.Rands = "changed-rands-after-email"
	require.NoError(t, user_model.UpdateUserCols(t.Context(), user, "rands"))

	verifiedUser := user_model.VerifyAccountRequestValidationCode(t.Context(), code)
	require.NotNil(t, verifiedUser)
	require.Equal(t, user.ID, verifiedUser.ID)
}

func TestAccountRequestValidationCodeMissingStatusFallback(t *testing.T) {
	require.NoError(t, unittest.PrepareTestDatabase())
	defer test.MockVariableValue(&setting.Service.RegisterManualConfirm, true)()

	user := &user_model.User{
		Name:   "account-request-missing-status-user",
		Email:  "account-request-missing-status-user@example.com",
		Passwd: "password",
	}
	require.NoError(t, user_model.CreateUser(t.Context(), user, &user_model.Meta{}))
	require.NoError(t, user_model.ResetAccountRequestToPendingEmailValidation(t.Context(), user))
	require.NoError(t, user_model.DeleteUserSetting(t.Context(), user.ID, user_model.SettingsKeyAccountRequestStatus))

	status, err := user_model.GetAccountRequestStatus(t.Context(), user)
	require.NoError(t, err)
	require.Equal(t, user_model.AccountRequestStatusPendingEmailValidation, status)

	code := user_model.GenerateAccountRequestValidationCode(user)
	verifiedUser := user_model.VerifyAccountRequestValidationCode(t.Context(), code)
	require.NotNil(t, verifiedUser)
	require.Equal(t, user.ID, verifiedUser.ID)
}

func TestAccountRequestValidationCodeIgnoresClassicActivation(t *testing.T) {
	require.NoError(t, unittest.PrepareTestDatabase())
	defer test.MockVariableValue(&setting.Service.RegisterEmailConfirm, true)()
	defer test.MockVariableValue(&setting.Service.RegisterManualConfirm, false)()

	user := &user_model.User{
		Name:   "classic-activation-user",
		Email:  "classic-activation-user@example.com",
		Passwd: "password",
	}
	require.NoError(t, user_model.CreateUser(t.Context(), user, &user_model.Meta{}))

	code := user_model.GenerateUserTimeLimitCode(&user_model.TimeLimitCodeOptions{Purpose: user_model.TimeLimitCodeActivateAccount}, user)
	require.Nil(t, user_model.VerifyAccountRequestValidationCode(t.Context(), code))
}
