using CMSMicroservice.Application.Common.Exceptions;
using CMSMicroservice.Application.Common.Interfaces;
using CMSMicroservice.Domain.Entities;
using CMSMicroservice.Domain.Events;
using Microsoft.EntityFrameworkCore;
namespace CMSMicroservice.Application.ProductsCQ.Commands.UpdateProducts;
public class UpdateProductsCommandHandler : IRequestHandler<UpdateProductsCommand, Unit>
{
    private readonly IApplicationDbContext _context;

    public UpdateProductsCommandHandler(IApplicationDbContext context)
    {
        _context = context;
    }

    public async Task<Unit> Handle(UpdateProductsCommand request, CancellationToken cancellationToken)
    {
        var entity = await _context.Products
            .FirstOrDefaultAsync(x => x.Id == request.Id, cancellationToken)
                     ?? throw new NotFoundException(nameof(Product), request.Id);

        request.Adapt(entity);
        _context.Products.Update(entity);

        // به‌روزرسانی دسته‌بندی‌های محصول در صورت ارسال CategoryIds
        if (request.CategoryIds is not null)
        {
            var targetIds = (request.CategoryIds ?? Array.Empty<long>())
                .Where(id => id > 0)
                .Distinct()
                .ToHashSet();

            var existingRelations = await _context.ProductCategories
                .Where(x => x.ProductId == entity.Id)
                .ToListAsync(cancellationToken);

            var existingIds = existingRelations
                .Select(x => x.CategoryId)
                .ToHashSet();

            var toAdd = targetIds.Except(existingIds).ToList();
            var toRemove = existingRelations.Where(x => !targetIds.Contains(x.CategoryId)).ToList();

            foreach (var categoryId in toAdd)
            {
                var rel = new ProductCategory
                {
                    ProductId = entity.Id,
                    CategoryId = categoryId
                };
                await _context.ProductCategories.AddAsync(rel, cancellationToken);
            }

            if (toRemove.Count > 0)
            {
                _context.ProductCategories.RemoveRange(toRemove);
            }
        }

        entity.AddDomainEvent(new UpdateProductsEvent(entity));
        await _context.SaveChangesAsync(cancellationToken);
        return Unit.Value;
    }
}
