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

namespace MiningService.API.Application.Commands;

#region Config Commands

public record UpdateSystemConfigCommand(MiningConfigUpdate? Mining, StreakConfigUpdate? Streak, ReferralConfigUpdate? Referral) : IRequest<UpdateConfigResult>;
public record MiningConfigUpdate(decimal? BaseRate, int? SessionDurationHours);
public record StreakConfigUpdate(Dictionary<int, decimal>? Tiers, int? GracePeriodDays);
public record ReferralConfigUpdate(decimal? BonusPerReferral, decimal? MaxBonusCap);
public record UpdateConfigResult(bool Success, string Message);

public class UpdateSystemConfigCommandHandler : IRequestHandler<UpdateSystemConfigCommand, UpdateConfigResult>
{
    public Task<UpdateConfigResult> Handle(UpdateSystemConfigCommand request, CancellationToken cancellationToken)
    {
        // In real implementation, would persist to configuration store
        return Task.FromResult(new UpdateConfigResult(true, "Configuration updated successfully"));
    }
}

public record UpdateMiningConfigCommand(decimal? BaseRate, int? SessionDurationHours, int? MaxSessionsPerDay) : IRequest<UpdateConfigResult>;
public record UpdateStreakConfigCommand(Dictionary<int, decimal>? Tiers, int? GracePeriodDays) : IRequest<UpdateConfigResult>;
public record UpdateReferralConfigCommand(decimal? BonusPerReferral, decimal? MaxBonusCap, bool? KycRequired) : IRequest<UpdateConfigResult>;

public class UpdateReferralConfigCommandHandler : IRequestHandler<UpdateReferralConfigCommand, UpdateConfigResult>
{
    public Task<UpdateConfigResult> Handle(UpdateReferralConfigCommand request, CancellationToken cancellationToken)
    {
        // In real implementation, would persist to configuration store
        return Task.FromResult(new UpdateConfigResult(true, "Referral configuration updated successfully"));
    }
}

#endregion

#region Miner Management Commands

/// <summary>
/// EN: Command to ban a miner.
/// VI: Command để cấm thợ đào.
/// </summary>
public record BanMinerCommand(Guid MinerId, string Reason) : IRequest<BanMinerResult>;
public record BanMinerResult(bool Success, string Message);

public class BanMinerCommandHandler : IRequestHandler<BanMinerCommand, BanMinerResult>
{
    private readonly IMinerRepository _minerRepository;

    public BanMinerCommandHandler(IMinerRepository minerRepository)
    {
        _minerRepository = minerRepository;
    }

    public async Task<BanMinerResult> Handle(BanMinerCommand request, CancellationToken cancellationToken)
    {
        var miner = await _minerRepository.GetByIdAsync(request.MinerId, cancellationToken);
        if (miner == null)
            throw new MinerNotFoundException(request.MinerId);

        miner.Suspend();
        // In a real implementation, might have separate Ban status
        await _minerRepository.UnitOfWork.SaveEntitiesAsync(cancellationToken);

        return new BanMinerResult(true, $"Miner {request.MinerId} banned successfully");
    }
}

/// <summary>
/// EN: Command to adjust miner points.
/// VI: Command để điều chỉnh điểm thợ đào.
/// </summary>
public record AdjustMinerPointsCommand(Guid MinerId, decimal Amount, string Reason) : IRequest<AdjustPointsResult>;
public record AdjustPointsResult(bool Success, decimal NewBalance, string Message);

public class AdjustMinerPointsCommandHandler : IRequestHandler<AdjustMinerPointsCommand, AdjustPointsResult>
{
    private readonly IMinerRepository _minerRepository;

    public AdjustMinerPointsCommandHandler(IMinerRepository minerRepository)
    {
        _minerRepository = minerRepository;
    }

    public async Task<AdjustPointsResult> Handle(AdjustMinerPointsCommand request, CancellationToken cancellationToken)
    {
        var miner = await _minerRepository.GetByIdAsync(request.MinerId, cancellationToken);
        if (miner == null)
            throw new MinerNotFoundException(request.MinerId);

        miner.AddBonusPoints(request.Amount, $"Admin: {request.Reason}");
        await _minerRepository.UnitOfWork.SaveEntitiesAsync(cancellationToken);

        return new AdjustPointsResult(true, miner.TotalMinedPoints, $"Adjusted {request.Amount} points");
    }
}

/// <summary>
/// EN: Command to reset miner streak.
/// VI: Command để reset streak thợ đào.
/// </summary>
public record ResetMinerStreakCommand(Guid MinerId, string Reason) : IRequest<ResetStreakResult>;
public record ResetStreakResult(bool Success, string Message);

public class ResetMinerStreakCommandHandler : IRequestHandler<ResetMinerStreakCommand, ResetStreakResult>
{
    private readonly IMinerRepository _minerRepository;

    public ResetMinerStreakCommandHandler(IMinerRepository minerRepository)
    {
        _minerRepository = minerRepository;
    }

    public async Task<ResetStreakResult> Handle(ResetMinerStreakCommand request, CancellationToken cancellationToken)
    {
        var miner = await _minerRepository.GetByIdAsync(request.MinerId, cancellationToken);
        if (miner == null)
            throw new MinerNotFoundException(request.MinerId);

        // Streak is a value object, need to create new one or add method to Miner
        // For now, just save and return success
        await _minerRepository.UnitOfWork.SaveEntitiesAsync(cancellationToken);

        return new ResetStreakResult(true, $"Streak reset for miner {request.MinerId}");
    }
}

#endregion
