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

package setting

import (
	"code.gitea.io/gitea/modules/container"
	"code.gitea.io/gitea/modules/log"
)

// Admin settings
var Admin struct {
	DisableRegularOrgCreation   bool
	DefaultEmailNotification    string
	SuperAdminEnabled           bool
	AdminManagementPolicy       string
	UserDisabledFeatures        container.Set[string]
	ExternalUserDisableFeatures container.Set[string]
}

const (
	AdminManagementPolicySuperAdminOnly     = "super_admin_only"
	AdminManagementPolicyGrantorOnly        = "grantor_only"
	AdminManagementPolicyGrantorInheritance = "grantor_inheritance"
	AdminManagementPolicyAdminsCanPromote   = "admins_can_promote_users"
	AdminManagementPolicySuperAdminApproval = "super_admin_approval"
	defaultAdminManagementPolicy            = AdminManagementPolicyGrantorOnly
)

var validAdminManagementPolicies = container.SetOf(
	AdminManagementPolicySuperAdminOnly,
	AdminManagementPolicyGrantorOnly,
	AdminManagementPolicyGrantorInheritance,
	AdminManagementPolicyAdminsCanPromote,
	AdminManagementPolicySuperAdminApproval,
)

var validUserFeatures = container.SetOf(
	UserFeatureDeletion,
	UserFeatureManageSSHKeys,
	UserFeatureManageGPGKeys,
	UserFeatureManageMFA,
	UserFeatureManageCredentials,
	UserFeatureChangeUsername,
	UserFeatureChangeFullName,
)

func loadAdminFrom(rootCfg ConfigProvider) {
	sec := rootCfg.Section("admin")
	Admin.DisableRegularOrgCreation = sec.Key("DISABLE_REGULAR_ORG_CREATION").MustBool(false)
	Admin.DefaultEmailNotification = sec.Key("DEFAULT_EMAIL_NOTIFICATIONS").MustString("enabled")
	Admin.SuperAdminEnabled = sec.Key("SUPER_ADMIN_ENABLED").MustBool(true)
	Admin.AdminManagementPolicy = normalizeAdminManagementPolicy(sec.Key("ADMIN_MANAGEMENT_POLICY").MustString(defaultAdminManagementPolicy))
	Admin.UserDisabledFeatures = container.SetOf(sec.Key("USER_DISABLED_FEATURES").Strings(",")...)
	Admin.ExternalUserDisableFeatures = container.SetOf(sec.Key("EXTERNAL_USER_DISABLE_FEATURES").Strings(",")...).Union(Admin.UserDisabledFeatures)

	if !validAdminManagementPolicies.Contains(Admin.AdminManagementPolicy) {
		log.Warn("ADMIN_MANAGEMENT_POLICY contains unknown policy %q, using %q", Admin.AdminManagementPolicy, defaultAdminManagementPolicy)
		Admin.AdminManagementPolicy = defaultAdminManagementPolicy
	}

	for feature := range Admin.UserDisabledFeatures {
		if !validUserFeatures.Contains(feature) {
			log.Warn("USER_DISABLED_FEATURES contains unknown feature %q", feature)
		}
	}
	for feature := range Admin.ExternalUserDisableFeatures {
		if !validUserFeatures.Contains(feature) && !Admin.UserDisabledFeatures.Contains(feature) {
			log.Warn("EXTERNAL_USER_DISABLE_FEATURES contains unknown feature %q", feature)
		}
	}
}

func normalizeAdminManagementPolicy(policy string) string {
	switch policy {
	case AdminManagementPolicyAdminsCanPromote:
		return AdminManagementPolicyGrantorOnly
	case AdminManagementPolicySuperAdminApproval:
		return AdminManagementPolicySuperAdminOnly
	default:
		return policy
	}
}

const (
	UserFeatureDeletion          = "deletion"
	UserFeatureManageSSHKeys     = "manage_ssh_keys"
	UserFeatureManageGPGKeys     = "manage_gpg_keys"
	UserFeatureManageMFA         = "manage_mfa"
	UserFeatureManageCredentials = "manage_credentials"
	UserFeatureChangeUsername    = "change_username"
	UserFeatureChangeFullName    = "change_full_name"
)
