package auth

import (
	stdErrors "errors"
	"fmt"
	"strings"
)

var ErrUserInfoProfileConflict = stdErrors.New("multiple OAuth userinfo profiles match request")

type UserInfoProfileClaims struct {
	ProfileID string
	Claims    map[string]any
}

func NormalizeUserInfoProfiles(profiles []UserInfoProfileRegistration) []UserInfoProfileRegistration {
	out := make([]UserInfoProfileRegistration, 0, len(profiles))
	seen := map[string]struct{}{}
	for _, profile := range profiles {
		profileID := NormalizeProductCapabilityToken(profile.ProfileID)
		if profileID == "" || profile.Applies == nil || profile.Build == nil {
			continue
		}
		if _, ok := seen[profileID]; ok {
			continue
		}
		seen[profileID] = struct{}{}
		profile.ProfileID = profileID
		out = append(out, profile)
	}
	return out
}

func BuildUserInfoProfileClaims(ctx UserInfoProfileContext, profiles []UserInfoProfileRegistration) (UserInfoProfileClaims, error) {
	var match UserInfoProfileClaims
	for _, profile := range NormalizeUserInfoProfiles(profiles) {
		if !profile.Applies(ctx) {
			continue
		}
		if match.ProfileID != "" {
			return UserInfoProfileClaims{}, fmt.Errorf("%w: %s and %s", ErrUserInfoProfileConflict, match.ProfileID, profile.ProfileID)
		}
		match = UserInfoProfileClaims{
			ProfileID: profile.ProfileID,
			Claims:    copyUserInfoProfileClaims(profile.Build(ctx)),
		}
	}
	return match, nil
}

func copyUserInfoProfileClaims(claims map[string]any) map[string]any {
	if len(claims) == 0 {
		return nil
	}
	copied := make(map[string]any, len(claims))
	for key, value := range claims {
		key = strings.TrimSpace(key)
		if key == "" {
			continue
		}
		copied[key] = value
	}
	return copied
}
