using MediatR;
using MiningService.Domain.AggregatesModel.MinerAggregate;
using MiningService.Domain.AggregatesModel.CircleAggregate;
using MiningService.Domain.AggregatesModel.ReferralAggregate;
using MiningService.Domain.AggregatesModel.ConfigurationAggregate;

namespace MiningService.API.Application.Queries;

#region Config Queries

public record GetSystemConfigQuery() : IRequest<SystemConfigDto>;

public record SystemConfigDto(
    MiningConfigDto Mining,
    StreakConfigDto Streak,
    ReferralConfigDto Referral);

public record MiningConfigDto(decimal BaseRate, int SessionDurationHours, int MaxSessionsPerDay, bool IsEnabled);
public record StreakConfigDto(Dictionary<int, decimal> Tiers, int GracePeriodHours, decimal RecoveryCost);
public record ReferralConfigDto(decimal BonusPerReferral, decimal MaxBonusCap, bool KycRequired);

public class GetSystemConfigQueryHandler : IRequestHandler<GetSystemConfigQuery, SystemConfigDto>
{
    private readonly IConfigurationRepository _configRepository;

    public GetSystemConfigQueryHandler(IConfigurationRepository configRepository)
    {
        _configRepository = configRepository;
    }

    public async Task<SystemConfigDto> Handle(GetSystemConfigQuery request, CancellationToken cancellationToken)
    {
        var mining = await _configRepository.GetMiningConfigAsync(cancellationToken);
        var streak = await _configRepository.GetStreakConfigAsync(cancellationToken);
        var referral = await _configRepository.GetReferralConfigAsync(cancellationToken);

        var tiers = streak.Tiers.ToDictionary(t => t.MinDays, t => t.BonusPercent);

        return new SystemConfigDto(
            new MiningConfigDto(mining.BaseRate, mining.SessionDurationHours, mining.MaxSessionsPerDay, mining.IsGloballyEnabled),
            new StreakConfigDto(tiers, streak.GracePeriodHours, streak.RecoveryCost),
            new ReferralConfigDto(referral.BonusPercentPerReferral, referral.MaxBonusPercent, referral.KycRequired));
    }
}

public record GetMiningConfigQuery() : IRequest<MiningConfigDto>;
public record GetStreakConfigQuery() : IRequest<StreakConfigDto>;
public record GetReferralConfigQuery() : IRequest<ReferralConfigDto>;

public class GetReferralConfigQueryHandler : IRequestHandler<GetReferralConfigQuery, ReferralConfigDto>
{
    private readonly IConfigurationRepository _configRepository;

    public GetReferralConfigQueryHandler(IConfigurationRepository configRepository)
    {
        _configRepository = configRepository;
    }

    public async Task<ReferralConfigDto> Handle(GetReferralConfigQuery request, CancellationToken cancellationToken)
    {
        var referral = await _configRepository.GetReferralConfigAsync(cancellationToken);
        return new ReferralConfigDto(referral.BonusPercentPerReferral, referral.MaxBonusPercent, referral.KycRequired);
    }
}

#endregion

#region Miners List Query

public record GetMinersListQuery(int Page = 1, int PageSize = 20, string? Search = null) : IRequest<MinersListDto>;

public record MinersListDto(List<MinerListItemDto> Items, int TotalCount, int Page, int PageSize);

public record MinerListItemDto(
    Guid Id,
    Guid UserId,
    string ReferralCode,
    MinerRole Role,
    MinerStatus Status,
    decimal TotalPoints,
    int StreakDays,
    DateTime CreatedAt);

public class GetMinersListQueryHandler : IRequestHandler<GetMinersListQuery, MinersListDto>
{
    private readonly IMinerRepository _minerRepository;

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

    public async Task<MinersListDto> Handle(GetMinersListQuery request, CancellationToken cancellationToken)
    {
        var miners = await _minerRepository.GetTopMinersAsync(request.PageSize * request.Page, cancellationToken);
        var items = miners
            .Skip((request.Page - 1) * request.PageSize)
            .Take(request.PageSize)
            .Select(m => new MinerListItemDto(
                m.Id, m.UserId, m.ReferralCode, m.Role, m.Status, 
                m.TotalMinedPoints, m.Streak.CurrentStreak, m.CreatedAt))
            .ToList();

        return new MinersListDto(items, miners.Count, request.Page, request.PageSize);
    }
}

public record GetMinerDetailsQuery(Guid MinerId) : IRequest<MinerDetailsDto?>;

public record MinerDetailsDto(
    Guid Id,
    Guid UserId,
    string ReferralCode,
    MinerRole Role,
    MinerStatus Status,
    decimal TotalPoints,
    decimal CurrentMiningRate,
    int StreakDays,
    int LongestStreak,
    Guid? CircleId,
    int ActiveReferralCount,
    DateTime CreatedAt,
    DateTime? LastMiningAt);

public class GetMinerDetailsQueryHandler : IRequestHandler<GetMinerDetailsQuery, MinerDetailsDto?>
{
    private readonly IMinerRepository _minerRepository;

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

    public async Task<MinerDetailsDto?> Handle(GetMinerDetailsQuery request, CancellationToken cancellationToken)
    {
        var miner = await _minerRepository.GetByIdAsync(request.MinerId, cancellationToken);
        if (miner == null) return null;

        return new MinerDetailsDto(
            miner.Id, miner.UserId, miner.ReferralCode, miner.Role, miner.Status,
            miner.TotalMinedPoints, miner.CurrentRate.TotalRate, miner.Streak.CurrentStreak,
            miner.Streak.LongestStreak, miner.CircleId, 0, // ActiveReferralCount needs query
            miner.CreatedAt, miner.Streak.LastMiningDate);
    }
}

#endregion

#region Analytics Queries

public record GetMinerAnalyticsQuery() : IRequest<MinerAnalyticsDto>;

public record MinerAnalyticsDto(
    int TotalMiners,
    int ActiveMiners,
    int SuspendedMiners,
    decimal TotalPointsMined,
    decimal PointsMinedToday,
    Dictionary<string, int> RoleDistribution);

public class GetMinerAnalyticsQueryHandler : IRequestHandler<GetMinerAnalyticsQuery, MinerAnalyticsDto>
{
    private readonly IMinerRepository _minerRepository;

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

    public async Task<MinerAnalyticsDto> Handle(GetMinerAnalyticsQuery request, CancellationToken cancellationToken)
    {
        var topMiners = await _minerRepository.GetTopMinersAsync(10000, cancellationToken);
        
        return new MinerAnalyticsDto(
            topMiners.Count,
            topMiners.Count(m => m.Status == MinerStatus.Active),
            topMiners.Count(m => m.Status == MinerStatus.Suspended),
            topMiners.Sum(m => m.TotalMinedPoints),
            topMiners.Where(m => m.UpdatedAt.Date == DateTime.UtcNow.Date).Sum(m => m.TotalMinedPoints),
            topMiners.GroupBy(m => m.Role.ToString()).ToDictionary(g => g.Key, g => g.Count()));
    }
}

public record GetCircleAnalyticsQuery() : IRequest<CircleAnalyticsDto>;

public record CircleAnalyticsDto(
    int TotalCircles,
    int ValidCircles,
    int AverageMembersPerCircle,
    decimal AverageTrustScore);

public class GetCircleAnalyticsQueryHandler : IRequestHandler<GetCircleAnalyticsQuery, CircleAnalyticsDto>
{
    private readonly ICircleRepository _circleRepository;

    public GetCircleAnalyticsQueryHandler(ICircleRepository circleRepository)
    {
        _circleRepository = circleRepository;
    }

    public async Task<CircleAnalyticsDto> Handle(GetCircleAnalyticsQuery request, CancellationToken cancellationToken)
    {
        // Simplified - would need full list query in real implementation
        return await Task.FromResult(new CircleAnalyticsDto(0, 0, 0, 0m));
    }
}

public record GetReferralAnalyticsQuery() : IRequest<ReferralAnalyticsDto>;

public record ReferralAnalyticsDto(
    int TotalReferrals,
    int ActiveReferrals,
    int PendingReferrals,
    decimal TotalBonusDistributed);

public class GetReferralAnalyticsQueryHandler : IRequestHandler<GetReferralAnalyticsQuery, ReferralAnalyticsDto>
{
    private readonly IReferralRepository _referralRepository;

    public GetReferralAnalyticsQueryHandler(IReferralRepository referralRepository)
    {
        _referralRepository = referralRepository;
    }

    public async Task<ReferralAnalyticsDto> Handle(GetReferralAnalyticsQuery request, CancellationToken cancellationToken)
    {
        // Simplified
        return await Task.FromResult(new ReferralAnalyticsDto(0, 0, 0, 0m));
    }
}

public record GetPointsAnalyticsQuery() : IRequest<PointsAnalyticsDto>;
public record PointsAnalyticsDto(decimal TotalPointsMined, decimal PointsMinedToday, decimal PointsMinedThisWeek, decimal AveragePerUser);

public record GetStreakAnalyticsQuery() : IRequest<StreakAnalyticsDto>;
public record StreakAnalyticsDto(int AverageStreak, int MaxStreak, int UsersWithStreak7Plus, int UsersWithStreak30Plus);

public record GetAuditLogsQuery(int Page = 1, int PageSize = 50) : IRequest<AuditLogsDto>;
public record AuditLogsDto(List<AuditLogItemDto> Items, int TotalCount);
public record AuditLogItemDto(Guid Id, string Action, string EntityType, Guid EntityId, string PerformedBy, DateTime Timestamp);

#endregion
