using System.Security.Cryptography; using Application.Abstractions.Data; using Application.Abstractions.Messaging; using Microsoft.EntityFrameworkCore; namespace Application.Features.Admin.Channel.List.GenerateDonationCode; internal sealed class Handler(IAppDbContext db) : IQueryHandler { // 혼동되는 문자(0/O, 1/I/L) 제외 31자. 6자리 조합 31^6 ≈ 8.8억. private const string Alphabet = "23456789ABCDEFGHJKMNPQRSTUVWXYZ"; private const int CodeLength = 6; private const int MaxAttempts = 10; public async Task Handle(Query request, CancellationToken ct) { for (var attempt = 0; attempt < MaxAttempts; attempt++) { var candidate = Generate(); var exists = await db.Channel.AnyAsync(c => c.DonationCode == candidate, ct); if (!exists) { return candidate; } } // 31^6 ≈ 8.8억 중 10회 모두 충돌은 극히 낮은 확률. 호출자 측 유효성 검증으로 한 번 더 안전망. return Generate(); } private static string Generate() { var chars = new char[CodeLength]; var bytes = new byte[CodeLength]; RandomNumberGenerator.Fill(bytes); for (var i = 0; i < CodeLength; i++) { chars[i] = Alphabet[bytes[i] % Alphabet.Length]; } return new string(chars); } }