using System.Text.RegularExpressions; using Application.Abstractions.Data; using Application.Abstractions.Messaging; using SharedKernel.Results; using Microsoft.EntityFrameworkCore; namespace Application.Features.Admin.Channel.List.Create; public sealed class Handler(IAppDbContext db) : ICommandHandler> { public async Task> Handle(Command request, CancellationToken ct) { var exists = await db.Channel.AnyAsync(c => c.SID == request.SID, ct); if (exists) { return Result.Failure(Error.Conflict("Channel.DuplicateSID", "이미 등록된 채널 SID입니다.")); } // 후원 코드 사전 검증: 형식 + 중복 (도메인 안전망 외 사용자 친화적 에러) string? normalizedDonationCode = null; if (!string.IsNullOrWhiteSpace(request.DonationCode)) { var trimmed = request.DonationCode.Trim(); if (!Regex.IsMatch(trimmed, "^[A-Za-z0-9]{4,7}$")) { return Result.Failure(Error.Problem("DonationCode.InvalidFormat", "후원 코드는 4~7자 영문/숫자만 가능합니다.")); } normalizedDonationCode = trimmed.ToUpperInvariant(); var codeTaken = await db.Channel.AnyAsync(c => c.DonationCode == normalizedDonationCode, ct); if (codeTaken) { return Result.Failure(Error.Conflict("DonationCode.Duplicate", "이미 사용 중인 후원 코드입니다.")); } } var channel = Domain.Entities.Members.Channel.Create( request.MemberID, request.SID, request.Name, request.YouTubeUrl ); channel.Update( request.Name, request.Handle, request.YouTubeUrl, request.PlatformFeeRate, request.StoreCommissionRate, request.IsVerified, request.IsActive ); channel.SetDonationCodeByAdmin(normalizedDonationCode); await db.Channel.AddAsync(channel, ct); try { await db.SaveChangesAsync(ct); } catch (DbUpdateException) { return Result.Failure(Error.Conflict("DonationCode.Duplicate", "이미 사용 중인 후원 코드입니다.")); } return Result.Success(channel.ID); } }