using Application.Abstractions.Data; using Application.Abstractions.Messaging; using Microsoft.EntityFrameworkCore; using System.Security.Cryptography; namespace Application.Features.Admin.Store.Game.GenerateCode; 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.Game.AnyAsync(c => c.Code == 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); } }