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

package admin

import (
	"strconv"

	user_model "code.gitea.io/gitea/models/user"
	"code.gitea.io/gitea/modules/log"
	"code.gitea.io/gitea/modules/setting"
	"code.gitea.io/gitea/modules/translation"
	"code.gitea.io/gitea/services/context"
	"code.gitea.io/gitea/services/mailer"
)

func loadAccountRequestData(ctx *context.Context, user *user_model.User) bool {
	status, err := user_model.GetAccountRequestStatus(ctx, user)
	if err != nil {
		ctx.ServerError("GetAccountRequestStatus", err)
		return false
	}
	ctx.Data["AccountRequestStatus"] = status

	attempts, err := user_model.GetAccountRequestSignupAttempts(ctx, user)
	if err != nil {
		ctx.ServerError("GetAccountRequestSignupAttempts", err)
		return false
	}
	ctx.Data["AccountRequestSignupAttempts"] = attempts

	mailStatus, err := user_model.GetAccountRequestValidationMailAttemptStatus(ctx, user)
	if err != nil {
		ctx.ServerError("GetAccountRequestValidationMailAttemptStatus", err)
		return false
	}
	ctx.Data["AccountRequestValidationMailAttemptStatus"] = mailStatus

	mailUnix, err := user_model.GetAccountRequestValidationMailAttemptUnix(ctx, user)
	if err != nil {
		ctx.ServerError("GetAccountRequestValidationMailAttemptUnix", err)
		return false
	}
	ctx.Data["AccountRequestValidationMailAttemptUnix"] = mailUnix
	return true
}

func accountRequestRedirect(ctx *context.Context, userID int64) {
	ctx.Redirect(setting.AppSubURL + "/-/admin/users/" + strconv.FormatInt(userID, 10) + "/edit")
}

func preparePendingAdminReviewAccountRequest(ctx *context.Context) (*user_model.User, bool) {
	u := prepareUserInfo(ctx)
	if ctx.Written() {
		return nil, false
	}
	status, err := user_model.GetAccountRequestStatus(ctx, u)
	if err != nil {
		ctx.ServerError("GetAccountRequestStatus", err)
		return nil, false
	}
	if status != user_model.AccountRequestStatusPendingAdminReview {
		ctx.Flash.Error(ctx.Tr("admin.users.account_request.invalid_action"))
		accountRequestRedirect(ctx, u.ID)
		return nil, false
	}
	return u, true
}

func AccountRequestActivate(ctx *context.Context) {
	u, ok := preparePendingAdminReviewAccountRequest(ctx)
	if !ok {
		return
	}
	if err := user_model.ApproveAccountRequest(ctx, u, ctx.Doer.ID); err != nil {
		ctx.ServerError("ApproveAccountRequest", err)
		return
	}
	if ok := storeAdminActivationInfo(ctx, u.ID, ctx.Doer); !ok {
		return
	}
	if err := mailer.SendAccountRequestApprovedMail(u); err != nil {
		log.Error("SendAccountRequestApprovedMail: %v", err)
	}
	log.Trace("Account request approved by admin (%s): %s", ctx.Doer.Name, u.Name)
	ctx.Flash.Success(ctx.Tr("admin.users.account_request.approved"))
	accountRequestRedirect(ctx, u.ID)
}

func AccountRequestReject(ctx *context.Context) {
	u, ok := preparePendingAdminReviewAccountRequest(ctx)
	if !ok {
		return
	}
	if err := user_model.RejectAccountRequest(ctx, u, ctx.Doer.ID); err != nil {
		ctx.ServerError("RejectAccountRequest", err)
		return
	}
	if ok := storeAdminProhibitLoginInfo(ctx, u.ID, ctx.Doer); !ok {
		return
	}
	if err := mailer.SendAccountRequestRejectedMail(u); err != nil {
		log.Error("SendAccountRequestRejectedMail: %v", err)
	}
	log.Trace("Account request rejected by admin (%s): %s", ctx.Doer.Name, u.Name)
	ctx.Flash.Success(ctx.Tr("admin.users.account_request.rejected"))
	accountRequestRedirect(ctx, u.ID)
}

func AccountRequestUnblock(ctx *context.Context) {
	u := prepareUserInfo(ctx)
	if ctx.Written() {
		return
	}
	status, err := user_model.GetAccountRequestStatus(ctx, u)
	if err != nil {
		ctx.ServerError("GetAccountRequestStatus", err)
		return
	}
	if status != user_model.AccountRequestStatusRejected && status != user_model.AccountRequestStatusBlocked {
		ctx.Flash.Error(ctx.Tr("admin.users.account_request.invalid_action"))
		accountRequestRedirect(ctx, u.ID)
		return
	}
	if err := user_model.UnblockAccountRequest(ctx, u); err != nil {
		ctx.ServerError("UnblockAccountRequest", err)
		return
	}
	validationCode := user_model.GenerateAccountRequestValidationCode(u)
	if err := mailer.SendAccountRequestValidationMail(translation.NewLocale(u.Language), u, validationCode); err != nil {
		if recordErr := user_model.RecordAccountRequestValidationMailAttempt(ctx, u.ID, false); recordErr != nil {
			log.Error("RecordAccountRequestValidationMailAttempt: %v", recordErr)
		}
		ctx.ServerError("SendAccountRequestValidationMail", err)
		return
	}
	if err := user_model.SetAccountRequestValidationCode(ctx, u.ID, validationCode); err != nil {
		ctx.ServerError("SetAccountRequestValidationCode", err)
		return
	}
	if err := user_model.RecordAccountRequestValidationMailAttempt(ctx, u.ID, true); err != nil {
		ctx.ServerError("RecordAccountRequestValidationMailAttempt", err)
		return
	}
	log.Trace("Account request unblocked by admin (%s): %s", ctx.Doer.Name, u.Name)
	ctx.Flash.Success(ctx.Tr("admin.users.account_request.unblocked"))
	accountRequestRedirect(ctx, u.ID)
}
