using MediatR;
using MiningService.Domain.AggregatesModel.CircleAggregate;
using MiningService.Domain.AggregatesModel.MinerAggregate;
using MiningService.Domain.Exceptions;

namespace MiningService.API.Application.Commands;

/// <summary>
/// EN: Handler for CreateCircleCommand.
/// VI: Handler cho CreateCircleCommand.
/// </summary>
public class CreateCircleCommandHandler : IRequestHandler<CreateCircleCommand, CreateCircleResult>
{
    private readonly ICircleRepository _circleRepository;
    private readonly IMinerRepository _minerRepository;

    public CreateCircleCommandHandler(
        ICircleRepository circleRepository,
        IMinerRepository minerRepository)
    {
        _circleRepository = circleRepository;
        _minerRepository = minerRepository;
    }

    public async Task<CreateCircleResult> Handle(CreateCircleCommand request, CancellationToken cancellationToken)
    {
        var miner = await _minerRepository.GetByUserIdAsync(request.UserId, cancellationToken)
            ?? throw new MinerNotFoundException($"Miner with UserId {request.UserId} not found");

        // Check if miner already owns a circle
        var existingCircle = await _circleRepository.GetByOwnerIdAsync(miner.Id, cancellationToken);
        if (existingCircle != null)
            throw new CircleDomainException("You already own a circle");

        // Check if miner is already in a circle
        if (miner.CircleId.HasValue)
            throw new CircleDomainException("You are already a member of a circle");

        var circle = Circle.Create(miner.Id, request.Name);
        _circleRepository.Add(circle);

        // Update miner's circle reference
        miner.JoinCircle(circle.Id);
        _minerRepository.Update(miner);

        await _circleRepository.UnitOfWork.SaveEntitiesAsync(cancellationToken);

        return new CreateCircleResult(circle.Id, circle.Name);
    }
}
