using Application.Abstractions.Messaging;
using Application.Abstractions.Data;
using Domain.Entities.Wallets.ValueObject;
using Microsoft.EntityFrameworkCore;

namespace Application.Features.Admin.Member.Wallet.Transactions.Search;

public sealed class Handler(IAppDbContext db) : IQueryHandler<Query, Response>
{
    public async Task<Response> Handle(Query request, CancellationToken ct)
    {
        var query = db.WalletTransaction.AsNoTracking().Include(x => x.Wallet).ThenInclude(w => w.Member).AsQueryable();

        // 거래 유형 필터
        if (request.Type.HasValue)
        {
            query = query.Where(x => x.TxType == request.Type.Value);
        }

        // 키워드 검색
        if (!string.IsNullOrWhiteSpace(request.Keyword))
        {
            query = request.Search switch
            {
                1 => query.Where(x => x.Wallet.Member.Email.Contains(request.Keyword)),
                2 => query.Where(x => x.ID.ToString().Contains(request.Keyword)),
                3 => query.Where(x => x.Wallet.ID.ToString().Contains(request.Keyword)),
                4 => query.Where(x => x.Wallet.MemberID.ToString().Contains(request.Keyword)),
                5 => query.Where(x => x.Wallet.Member.Name != null && x.Wallet.Member.Name.Contains(request.Keyword)),
                _ => query
            };
        }

        // 날짜 필터
        if (!string.IsNullOrWhiteSpace(request.StartAt) && DateTime.TryParse(request.StartAt, out var startAt))
        {
            query = query.Where(x => x.CreatedAt >= startAt);
        }

        if (!string.IsNullOrWhiteSpace(request.EndAt) && DateTime.TryParse(request.EndAt, out var endAt))
        {
            query = query.Where(x => x.CreatedAt <= endAt);
        }

        var total = await query.CountAsync(ct);

        // 유형별 카운트 (GroupBy 1회 쿼리)
        var typeCounts = await db.WalletTransaction.AsNoTracking().GroupBy(x => x.TxType).Select(g => new { Type = g.Key, Count = g.Count() }).ToListAsync(ct);
        int CountOf(WalletTransactionType t) => typeCounts.FirstOrDefault(x => x.Type == t)?.Count ?? 0;

        var skip = (request.PageNum - 1) * request.PerPage;

        var list = await query.OrderByDescending(x => x.ID).Skip(skip).Take(request.PerPage).Select(x => new { x.ID, x.WalletKey, MemberID = x.Wallet.MemberID, MemberEmail = x.Wallet.Member.Email, MemberName = x.Wallet.Member.Name, x.TxType, x.BalanceType, Amount = x.Amount.Value, BalanceAfter = x.BalanceAfter.Value, x.Reason, x.RefID, x.Memo, x.CreatedAt }).ToListAsync(ct);

        var rows = list.Select((x, idx) => new Response.Row
        {
            Num = total - skip - idx,
            ID = x.ID,
            WalletKey = x.WalletKey,
            MemberID = x.MemberID,
            MemberEmail = x.MemberEmail,
            MemberName = x.MemberName,
            TxType = x.TxType,
            BalanceType = x.BalanceType,
            Amount = (long)x.Amount,
            BalanceAfter = (long)x.BalanceAfter,
            Reason = x.Reason,
            RefID = x.RefID,
            Memo = x.Memo,
            CreatedAt = x.CreatedAt
        }).ToList();

        return new Response
        {
            Total = total,
            TotalCharge = CountOf(WalletTransactionType.Charge),
            TotalDonationIn = CountOf(WalletTransactionType.DonationIn),
            TotalDonationOut = CountOf(WalletTransactionType.DonationOut),
            TotalRewardEarned = CountOf(WalletTransactionType.RewardEarned),
            TotalSpend = CountOf(WalletTransactionType.Spend),
            TotalRefund = CountOf(WalletTransactionType.Refund),
            TotalLock = CountOf(WalletTransactionType.Lock),
            TotalUnlock = CountOf(WalletTransactionType.Unlock),
            TotalAdjusted = CountOf(WalletTransactionType.Adjusted),
            List = rows
        };
    }
}