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

package user

import (
	"context"

	"code.gitea.io/gitea/models/db"
	"code.gitea.io/gitea/modules/optional"
)

const (
	// SettingsKeyHiddenCommentTypes is the setting key for hidden comment types
	SettingsKeyHiddenCommentTypes = "issue.hidden_comment_types"
	// SettingsKeyPersistentFooter is the setting key for whether the footer remains visible in the viewport
	SettingsKeyPersistentFooter = "ui.persistent_footer"
	// SettingsKeyPersistentNavbar is the setting key for whether the navigation bar remains visible in the viewport
	SettingsKeyPersistentNavbar = "ui.persistent_navbar"
	// SettingsKeyStickySideMenus is the setting key for whether settings/admin side menus remain visible while scrolling
	SettingsKeyStickySideMenus = "ui.sticky_side_menus"
	// SettingsKeyDiffWhitespaceBehavior is the setting key for whitespace behavior of diff
	SettingsKeyDiffWhitespaceBehavior = "diff.whitespace_behaviour"
	// SettingsKeyShowOutdatedComments is the setting key whether or not to show outdated comments in PRs
	SettingsKeyShowOutdatedComments = "comment_code.show_outdated"

	// SignupIP is the IP address that the user signed up with
	SignupIP = "signup.ip"
	// SignupUserAgent is the user agent that the user signed up with
	SignupUserAgent = "signup.user_agent"

	SettingsKeyCodeViewShowFileTree = "code_view.show_file_tree"

	SettingsKeyEmailNotificationNewAccountRequests     = "email_notification.new_account_requests"
	SettingEmailNotificationNewAccountRequestsEnabled  = "enabled"
	SettingEmailNotificationNewAccountRequestsDisabled = "disabled"
	SettingsKeyEmailNotificationGiteaActions           = "email_notification.gitea_actions"
	SettingEmailNotificationGiteaActionsAll            = "all"
	SettingEmailNotificationGiteaActionsFailureOnly    = "failure-only" // Default for actions email preference
	SettingEmailNotificationGiteaActionsDisabled       = "disabled"

	SettingsKeyActionsConfig = "actions.config"
)

func GetEmailNotificationNewAccountRequestsPreference(ctx context.Context, user *User) (string, error) {
	def := SettingEmailNotificationNewAccountRequestsDisabled
	if user.IsAdmin {
		def = SettingEmailNotificationNewAccountRequestsEnabled
	}

	return GetUserSetting(ctx, user.ID, SettingsKeyEmailNotificationNewAccountRequests, def)
}

func IsEmailNotificationNewAccountRequestsEnabled(ctx context.Context, user *User) (bool, error) {
	preference, err := GetEmailNotificationNewAccountRequestsPreference(ctx, user)
	if err != nil {
		return false, err
	}

	return preference == SettingEmailNotificationNewAccountRequestsEnabled, nil
}

func CountAdminsWithNewAccountRequestNotificationsEnabled(ctx context.Context) (int, error) {
	admins, _, err := SearchUsers(ctx, SearchUserOptions{
		Types:       []UserType{UserTypeIndividual},
		IsAdmin:     optional.Some(true),
		IsActive:    optional.Some(true),
		ListOptions: db.ListOptionsAll,
	})
	if err != nil {
		return 0, err
	}

	count := 0
	for _, admin := range admins {
		enabled, err := IsEmailNotificationNewAccountRequestsEnabled(ctx, admin)
		if err != nil {
			return 0, err
		}
		if enabled {
			count++
		}
	}

	return count, nil
}

func IsLastAdminWithNewAccountRequestNotificationsEnabled(ctx context.Context, user *User) (bool, error) {
	if !user.IsAdmin || !user.IsActive {
		return false, nil
	}

	enabled, err := IsEmailNotificationNewAccountRequestsEnabled(ctx, user)
	if err != nil {
		return false, err
	}
	if !enabled {
		return false, nil
	}

	count, err := CountAdminsWithNewAccountRequestNotificationsEnabled(ctx)
	if err != nil {
		return false, err
	}

	return count <= 1, nil
}

func ShouldEnableNewAccountRequestNotificationsFallback(ctx context.Context, actor, target *User) (bool, error) {
	if actor == nil || target == nil || actor.ID == target.ID {
		return false, nil
	}
	if !actor.IsAdmin || !actor.IsActive {
		return false, nil
	}

	targetIsLastNotifier, err := IsLastAdminWithNewAccountRequestNotificationsEnabled(ctx, target)
	if err != nil {
		return false, err
	}
	if !targetIsLastNotifier {
		return false, nil
	}

	actorEnabled, err := IsEmailNotificationNewAccountRequestsEnabled(ctx, actor)
	if err != nil {
		return false, err
	}

	return !actorEnabled, nil
}
