package registration

import (
	"context"
	"fmt"
	"strings"
	"time"

	"github.com/tidbcloud/AgentTeam/internal/core/authidentity"
)

type UserRecord struct {
	ID               string
	Email            string
	Mobile           string
	Name             string
	DisplayName      string
	AvatarURL        string
	IsAdmin          bool
	PasswordHash     string
	EmailVerifiedAt  *time.Time
	MobileVerifiedAt *time.Time
	CreatedAt        time.Time
	UpdatedAt        time.Time
}

type UserRecordParams struct {
	ID               string
	Email            string
	Mobile           string
	Name             string
	DisplayName      string
	AvatarURL        string
	IsAdmin          bool
	PasswordHash     string
	EmailVerifiedAt  *time.Time
	MobileVerifiedAt *time.Time
	Now              time.Time
}

func BuildUserRecord(params UserRecordParams) UserRecord {
	now := params.Now.UTC()
	return UserRecord{
		ID:               params.ID,
		Email:            params.Email,
		Mobile:           params.Mobile,
		Name:             params.Name,
		DisplayName:      params.DisplayName,
		AvatarURL:        params.AvatarURL,
		IsAdmin:          params.IsAdmin,
		PasswordHash:     params.PasswordHash,
		EmailVerifiedAt:  params.EmailVerifiedAt,
		MobileVerifiedAt: params.MobileVerifiedAt,
		CreatedAt:        now,
		UpdatedAt:        now,
	}
}

func EmailVerifiedAt(verified bool, now time.Time) *time.Time {
	if !verified {
		return nil
	}
	verifiedAt := now.UTC()
	return &verifiedAt
}

func DisplayNameFromEmail(email string) string {
	localPart := strings.TrimSpace(strings.SplitN(email, "@", 2)[0])
	if localPart == "" {
		return "user"
	}
	return localPart
}

func PreferredDisplayName(values ...string) string {
	for _, value := range values {
		trimmed := strings.TrimSpace(value)
		if trimmed != "" {
			return trimmed
		}
	}
	return ""
}

func LegacyTargetKeys(preferred string, aliases ...string) []string {
	normalizedPreferred := strings.ToLower(strings.TrimSpace(preferred))
	if normalizedPreferred == "" {
		return nil
	}

	keys := make([]string, 0, len(aliases))
	seen := make(map[string]struct{}, len(aliases))
	for _, alias := range aliases {
		trimmed := strings.TrimSpace(alias)
		if trimmed == "" {
			continue
		}
		normalized := strings.ToLower(trimmed)
		if normalized == normalizedPreferred {
			continue
		}
		if _, exists := seen[normalized]; exists {
			continue
		}
		seen[normalized] = struct{}{}
		keys = append(keys, trimmed)
	}
	if len(keys) == 0 {
		return nil
	}
	return keys
}

type AllowlistEntryInput struct {
	Pattern string
	Reason  string
}

func NormalizeAllowlistEntryInput(pattern string, reason string) (AllowlistEntryInput, error) {
	normalizedPattern, err := authidentity.NormalizeEmailAllowlistPattern(pattern)
	if err != nil {
		return AllowlistEntryInput{}, err
	}
	return AllowlistEntryInput{
		Pattern: normalizedPattern,
		Reason:  strings.TrimSpace(reason),
	}, nil
}

func PingCAPNameSeed(displayName string, email string) string {
	name := strings.TrimSpace(displayName)
	if name == "" {
		name = strings.SplitN(strings.TrimSpace(email), "@", 2)[0]
	}
	name = strings.TrimSpace(name)
	if name == "" {
		name = "user"
	}
	return name
}

func NextUniqueName(ctx context.Context, seed string, exists func(context.Context, string) (bool, error)) (string, error) {
	if exists == nil {
		return "", fmt.Errorf("registration name existence checker is nil")
	}
	baseName := PingCAPNameSeed(seed, "")
	uniqueName := baseName
	for counter := 1; ; counter++ {
		alreadyExists, err := exists(ctx, uniqueName)
		if err != nil {
			return "", err
		}
		if !alreadyExists {
			return uniqueName, nil
		}
		uniqueName = fmt.Sprintf("%s%d", baseName, counter)
	}
}
