namespace WalletService.API.Application.Queries;

using MediatR;
using Microsoft.EntityFrameworkCore;
using WalletService.Domain.AggregatesModel.WalletAggregate;
using WalletService.Infrastructure;

/// <summary>
/// EN: Handler for GetAllWalletsQuery (Admin).
/// VI: Handler cho GetAllWalletsQuery (Admin).
/// </summary>
public class GetAllWalletsQueryHandler : IRequestHandler<GetAllWalletsQuery, AdminWalletsListDto>
{
    private readonly WalletServiceContext _context;

    public GetAllWalletsQueryHandler(WalletServiceContext context)
    {
        _context = context;
    }

    public async Task<AdminWalletsListDto> Handle(
        GetAllWalletsQuery request, 
        CancellationToken cancellationToken)
    {
        var query = _context.Wallets
            .Include(w => w.Balances)
            .AsQueryable();

        // EN: Filter by status if provided
        // VI: Lọc theo trạng thái nếu có
        if (!string.IsNullOrEmpty(request.Status))
        {
            var status = WalletStatus.FromDisplayName<WalletStatus>(request.Status);
            if (status != null)
                query = query.Where(w => w.StatusId == status.Id);
        }

        var totalCount = await query.CountAsync(cancellationToken);

        var wallets = await query
            .OrderByDescending(w => w.CreatedAt)
            .Skip((request.Page - 1) * request.PageSize)
            .Take(request.PageSize)
            .Select(w => new AdminWalletSummaryDto(
                w.Id,
                w.UserId,
                WalletStatus.FromValue<WalletStatus>(w.StatusId).Name,
                w.Balances.Select(b => new BalanceItemDto(
                    CurrencyType.FromValue<CurrencyType>(b.CurrencyTypeId).Name,
                    b.Balance)).ToList(),
                w.CreatedAt,
                w.UpdatedAt))
            .ToListAsync(cancellationToken);

        return new AdminWalletsListDto(wallets, totalCount, request.Page, request.PageSize);
    }
}

/// <summary>
/// EN: Handler for GetWalletByIdQuery (Admin).
/// VI: Handler cho GetWalletByIdQuery (Admin).
/// </summary>
public class GetWalletByIdQueryHandler : IRequestHandler<GetWalletByIdQuery, AdminWalletDetailDto?>
{
    private readonly WalletServiceContext _context;

    public GetWalletByIdQueryHandler(WalletServiceContext context)
    {
        _context = context;
    }

    public async Task<AdminWalletDetailDto?> Handle(
        GetWalletByIdQuery request, 
        CancellationToken cancellationToken)
    {
        var wallet = await _context.Wallets
            .Include(w => w.Balances)
            .Include(w => w.Transactions)
            .FirstOrDefaultAsync(w => w.Id == request.WalletId, cancellationToken);

        if (wallet == null) return null;

        return new AdminWalletDetailDto(
            wallet.Id,
            wallet.UserId,
            WalletStatus.FromValue<WalletStatus>(wallet.StatusId).Name,
            wallet.Balances.Select(b => new BalanceItemDto(
                CurrencyType.FromValue<CurrencyType>(b.CurrencyTypeId).Name,
                b.Balance)).ToList(),
            wallet.Transactions.Count,
            wallet.CreatedAt,
            wallet.UpdatedAt);
    }
}

/// <summary>
/// EN: Handler for SearchWalletsQuery (Admin).
/// VI: Handler cho SearchWalletsQuery (Admin).
/// </summary>
public class SearchWalletsQueryHandler : IRequestHandler<SearchWalletsQuery, List<AdminWalletDetailDto>>
{
    private readonly WalletServiceContext _context;

    public SearchWalletsQueryHandler(WalletServiceContext context)
    {
        _context = context;
    }

    public async Task<List<AdminWalletDetailDto>> Handle(
        SearchWalletsQuery request, 
        CancellationToken cancellationToken)
    {
        var query = _context.Wallets
            .Include(w => w.Balances)
            .Include(w => w.Transactions)
            .AsQueryable();

        if (request.UserId.HasValue)
            query = query.Where(w => w.UserId == request.UserId.Value);

        if (request.WalletId.HasValue)
            query = query.Where(w => w.Id == request.WalletId.Value);

        if (!string.IsNullOrEmpty(request.Status))
        {
            var status = WalletStatus.FromDisplayName<WalletStatus>(request.Status);
            if (status != null)
                query = query.Where(w => w.StatusId == status.Id);
        }

        var wallets = await query
            .Take(50) // Limit results
            .Select(w => new AdminWalletDetailDto(
                w.Id,
                w.UserId,
                WalletStatus.FromValue<WalletStatus>(w.StatusId).Name,
                w.Balances.Select(b => new BalanceItemDto(
                    CurrencyType.FromValue<CurrencyType>(b.CurrencyTypeId).Name,
                    b.Balance)).ToList(),
                w.Transactions.Count,
                w.CreatedAt,
                w.UpdatedAt))
            .ToListAsync(cancellationToken);

        return wallets;
    }
}

/// <summary>
/// EN: Handler for GetWalletStatisticsQuery (Admin).
/// VI: Handler cho GetWalletStatisticsQuery (Admin).
/// </summary>
public class GetWalletStatisticsQueryHandler : IRequestHandler<GetWalletStatisticsQuery, WalletStatisticsDto>
{
    private readonly WalletServiceContext _context;

    public GetWalletStatisticsQueryHandler(WalletServiceContext context)
    {
        _context = context;
    }

    public async Task<WalletStatisticsDto> Handle(
        GetWalletStatisticsQuery request, 
        CancellationToken cancellationToken)
    {
        var today = DateTime.UtcNow.Date;

        var totalWallets = await _context.Wallets.CountAsync(cancellationToken);
        var activeWallets = await _context.Wallets
            .CountAsync(w => w.StatusId == WalletStatus.Active.Id, cancellationToken);
        var frozenWallets = await _context.Wallets
            .CountAsync(w => w.StatusId == WalletStatus.Frozen.Id, cancellationToken);
        var closedWallets = await _context.Wallets
            .CountAsync(w => w.StatusId == WalletStatus.Closed.Id, cancellationToken);

        // EN: Total balance by currency
        // VI: Tổng số dư theo loại tiền tệ
        var balancesByCurrency = await _context.WalletItems
            .GroupBy(wi => wi.CurrencyTypeId)
            .Select(g => new { CurrencyId = g.Key, Total = g.Sum(wi => wi.Balance) })
            .ToListAsync(cancellationToken);

        var totalBalanceByCurrency = balancesByCurrency.ToDictionary(
            b => CurrencyType.FromValue<CurrencyType>(b.CurrencyId).Name,
            b => b.Total);

        // EN: Today's transactions
        // VI: Giao dịch hôm nay
        var todayTransactions = await _context.WalletTransactions
            .Where(t => t.CreatedAt >= today)
            .SumAsync(t => t.Amount.Amount, cancellationToken);

        var todayDeposits = await _context.WalletTransactions
            .Where(t => t.CreatedAt >= today && t.TypeId == TransactionType.Credit.Id)
            .SumAsync(t => t.Amount.Amount, cancellationToken);

        var todayWithdrawals = await _context.WalletTransactions
            .Where(t => t.CreatedAt >= today && t.TypeId == TransactionType.Debit.Id)
            .SumAsync(t => t.Amount.Amount, cancellationToken);

        return new WalletStatisticsDto(
            totalWallets,
            activeWallets,
            frozenWallets,
            closedWallets,
            totalBalanceByCurrency,
            todayTransactions,
            todayDeposits,
            todayWithdrawals);
    }
}
