using Application.Abstractions.Data;
using Application.Abstractions.Messaging;
using Microsoft.EntityFrameworkCore;
using SharedKernel.Results;
namespace Application.Features.Api.Member.Items.Equip;
///
/// 지위 아이템 장착. 슬롯당 1개만 장착 가능하므로, 같은 슬롯에 이미 장착된 아이템은 자동 해제한 뒤 장착한다.
/// (필터 유니크 인덱스 [MemberID, EquipSlot] WHERE IsEquipped=1 로 DB 레벨에서도 강제)
///
internal sealed class Handler(IAppDbContext db) : ICommandHandler>
{
public async Task> Handle(Command request, CancellationToken ct)
{
var now = DateTime.UtcNow;
var item = await db.MemberItem.FirstOrDefaultAsync(i => i.ID == request.MemberItemID, ct);
if (item is null || item.MemberID != request.MemberID)
{
return Result.Failure(Error.NotFound("MemberItem.NotFound", "보유 아이템을 찾을 수 없습니다."));
}
if (item.EquipSlot is null)
{
return Result.Failure(Error.Problem("MemberItem.NotEquippable", "장착할 수 없는 아이템입니다."));
}
if (item.RevokedAt is not null)
{
return Result.Failure(Error.Conflict("MemberItem.Revoked", "회수된 아이템입니다."));
}
if (item.IsExpiredAt(now))
{
return Result.Failure(Error.Conflict("MemberItem.Expired", "만료된 아이템입니다."));
}
if (item.IsEquipped)
{
return Result.Success(new Response(item.ID, item.EquipSlot.Value, true));
}
var slot = item.EquipSlot.Value;
// 같은 슬롯의 기존 장착 아이템 해제 (슬롯당 1개)
var current = await db.MemberItem
.Where(i => i.MemberID == request.MemberID && i.EquipSlot == slot && i.IsEquipped && i.ID != item.ID)
.ToListAsync(ct);
foreach (var equipped in current)
{
equipped.Unequip();
}
item.Equip(now);
await db.SaveChangesAsync(ct);
return Result.Success(new Response(item.ID, slot, true));
}
}