using MediatR;
using Microsoft.EntityFrameworkCore;
using ColaFlow.Modules.ProjectManagement.Application.Common.Interfaces;
using ColaFlow.Modules.ProjectManagement.Domain.Repositories;
using ColaFlow.Modules.ProjectManagement.Domain.ValueObjects;
using ColaFlow.Modules.ProjectManagement.Domain.Exceptions;
using ColaFlow.Modules.ProjectManagement.Domain.Events;

namespace ColaFlow.Modules.ProjectManagement.Application.Commands.UpdateSprint;

/// <summary>
/// Handler for UpdateSprintCommand
/// </summary>
public sealed class UpdateSprintCommandHandler(
    IApplicationDbContext context,
    IUnitOfWork unitOfWork,
    IMediator mediator)
    : IRequestHandler<UpdateSprintCommand, Unit>
{
    private readonly IApplicationDbContext _context = context ?? throw new ArgumentNullException(nameof(context));
    private readonly IUnitOfWork _unitOfWork = unitOfWork ?? throw new ArgumentNullException(nameof(unitOfWork));
    private readonly IMediator _mediator = mediator ?? throw new ArgumentNullException(nameof(mediator));

    public async Task<Unit> Handle(UpdateSprintCommand request, CancellationToken cancellationToken)
    {
        // Get sprint with tracking
        var sprintId = SprintId.From(request.SprintId);
        var sprint = await _context.Sprints
            .FirstOrDefaultAsync(s => s.Id == sprintId, cancellationToken);

        if (sprint == null)
            throw new NotFoundException("Sprint", request.SprintId);

        // Update sprint details
        sprint.UpdateDetails(
            request.Name,
            request.Goal,
            request.StartDate,
            request.EndDate
        );

        // Save changes
        await _unitOfWork.SaveChangesAsync(cancellationToken);

        // Publish domain event
        await _mediator.Publish(new SprintUpdatedEvent(sprint.Id.Value, sprint.Name, sprint.ProjectId.Value), cancellationToken);

        return Unit.Value;
    }
}
