using Application.Abstractions.Data;
using Application.Abstractions.Messaging;
using Domain.Entities.Wallets.Policy;
using Microsoft.EntityFrameworkCore;
using SharedKernel.Results;

namespace Application.Features.Api.MyPage.Dropdown;

public sealed class Handler(IAppDbContext db) : IQueryHandler<Query, Result<Response>>
{
    public async Task<Result<Response>> Handle(Query request, CancellationToken ct)
    {
        var member = await db.Member.AsNoTracking()
            .Where(m => m.ID == request.MemberID)
            .Select(m => new { m.SID, m.Name, m.Thumb, m.IsCreator })
            .FirstOrDefaultAsync(ct);

        if (member is null)
        {
            return Result.Failure<Response>(Error.NotFound("Member.NotFound", "회원을 찾을 수 없습니다."));
        }

        // 후원 가능 잔액 (SpendPolicy 순서의 잔액 합산)
        var spendableBalance = 0m;
        var wallet = await db.Wallet.AsNoTracking()
            .Include(w => w.Balances)
            .FirstOrDefaultAsync(w => w.MemberID == request.MemberID, ct);

        if (wallet is not null)
        {
            foreach (var balanceType in SpendPolicy.DefaultSpendOrder)
            {
                var balance = wallet.Balances.FirstOrDefault(b => b.Type == balanceType);
                if (balance is not null)
                {
                    spendableBalance += balance.Amount.Value;
                }
            }
        }

        // 채널 조회
        int? channelID = null;
        decimal? withdrawableBalance = null;
        var channel = await db.Channel.AsNoTracking()
            .FirstOrDefaultAsync(c => c.MemberID == request.MemberID && c.IsActive, ct);

        if (channel is not null)
        {
            channelID = channel.ID;

            if (wallet is not null)
            {
                var donationBalance = wallet.Balances
                    .FirstOrDefault(b => b.Type == Domain.Entities.Wallets.ValueObject.WalletBalanceType.Donation);
                withdrawableBalance = donationBalance?.Amount.Value ?? 0;
            }
        }

        return new Response(
            member.SID,
            member.Name,
            member.Thumb,
            member.IsCreator,
            channelID,
            (int)spendableBalance,
            withdrawableBalance.HasValue ? (int)withdrawableBalance.Value : null
        );
    }
}