using CMSMicroservice.Protobuf.Protos.Commission;

namespace FrontOffice.Main.Utilities;

/// <summary>
/// Service for Commission operations
/// Connected to FrontOffice.BFF gRPC CommissionCQ
/// </summary>
public class CommissionService
{
    private readonly CommissionContract.CommissionContractClient _client;

    public CommissionService(CommissionContract.CommissionContractClient client)
    {
        _client = client;
    }

    /// <summary>
    /// Get week definitions for dropdown
    /// Maps to: CommissionCQ.GetWeekDefinitions
    /// </summary>
    public async Task<List<WeekDefinitionDto>> GetWeekDefinitionsAsync(
        string? searchText = null,
        int? gregorianYear = null,
        int? persianYear = null,
        bool? isActive = null,
        int pageSize = 100)
    {
        try
        {
            var request = new GetWeekDefinitionsRequest
            {
                PageNumber = 1,
                PageSize = pageSize
            };
            
            if (!string.IsNullOrWhiteSpace(searchText))
                request.SearchText = searchText;
            
            if (gregorianYear.HasValue)
                request.GregorianYear = gregorianYear.Value;
            
            if (persianYear.HasValue)
                request.PersianYear = persianYear.Value;
            
            if (isActive.HasValue)
                request.IsActive = isActive.Value;
            
            var response = await _client.GetWeekDefinitionsAsync(request);
            
            return response.Data.Select(w => new WeekDefinitionDto
            {
                Id = w.Id,
                WeekOrder = w.WeekOrder,
                DisplayName = w.DisplayName,
                StartDate = w.StartDate?.ToDateTime() ?? DateTime.MinValue,
                EndDate = w.EndDate?.ToDateTime() ?? DateTime.MinValue,
                GregorianYear = w.GregorianYear,
                PersianYear = w.PersianYear,
                IsActive = w.IsActive,
                IsCurrentWeek = w.IsCurrentWeek,
                StartDatePersian = w.StartDatePersian,
                EndDatePersian = w.EndDatePersian
            }).ToList();
        }
        catch
        {
            // Return empty list if backend is unavailable
            return new List<WeekDefinitionDto>();
        }
    }

    /// <summary>
    /// Get commission payouts with pagination and filters
    /// Maps to: CommissionCQ.GetMyCommissionPayouts
    /// </summary>
    public async Task<CommissionPayoutsResponseDto> GetMyCommissionPayoutsAsync(
        long? weekDefinitionId,
        string? status,
        int pageNumber,
        int pageSize,
        long? packageId = null)
    {
        try
        {
            var request = new GetMyCommissionPayoutsRequest
            {
                PageNumber = pageNumber,
                PageSize = pageSize
            };
            
            if (weekDefinitionId.HasValue)
            {
                request.WeekDefinitionId = weekDefinitionId.Value;
            }
            
            // Map status string to int
            if (!string.IsNullOrEmpty(status))
            {
                request.Status = status switch
                {
                    "Pending" or "در انتظار" or "Created" or "ایجاد شده" => 0,
                    "Paid" or "پرداخت شده" => 1,
                    "WithdrawalRequested" or "درخواست برداشت" => 2,
                    "Withdrawn" or "برداشت شده" => 3,
                    "PaymentFailed" or "شکست خورده" => 4,
                    "Cancelled" or "لغو شده" => 5,
                    _ => null
                };
            }

            if (packageId.HasValue && packageId.Value > 0)
            {
                request.PackageId = packageId.Value;
            }
            
            var response = await _client.GetMyCommissionPayoutsAsync(request);
            
            return new CommissionPayoutsResponseDto
            {
                Payouts = response.Payouts.Select(p => new CommissionPayoutDto
                {
                    Id = p.Id,
                    WeekDefinitionId = p.WeekDefinitionId,
                    WeekDisplayName = p.WeekDisplayName,
                    BalancesEarned = p.BalancesEarned,
                    TotalAmount = p.TotalAmount,
                    AmountFormatted = p.AmountFormatted,
                    Status = p.Status,
                    DatePersian = p.DatePersian,
                    PackageId = p.PackageId,
                    PackageTitle = p.PackageTitle
                }).ToList(),
                TotalCount = (int)(response.MetaData?.TotalCount ?? 0),
                PageNumber = pageNumber,
                PageSize = pageSize
            };
        }
        catch
        {
            // Return empty response if backend is unavailable
            return new CommissionPayoutsResponseDto
            {
                Payouts = new List<CommissionPayoutDto>(),
                TotalCount = 0,
                PageNumber = pageNumber,
                PageSize = pageSize
            };
        }
    }

    /// <summary>
    /// Get weekly balance details for a specific week
    /// Maps to: CommissionCQ.GetMyWeeklyBalances
    /// </summary>
    public async Task<WeeklyBalanceDto> GetMyWeeklyBalanceAsync(long? weekDefinitionId = null, long? packageId = null)
    {
        try
        {
            var request = new GetMyWeeklyBalancesRequest
            {
                PageNumber = 1,
                PageSize = 1,
                OnlyActive = false
            };
            
            if (weekDefinitionId.HasValue)
            {
                request.WeekDefinitionId = weekDefinitionId.Value;
            }else
            {
                request.WeekDefinitionId=7;
            }

            if (packageId.HasValue && packageId.Value > 0)
            {
                request.PackageId = packageId.Value;
            }
            
            var response = await _client.GetMyWeeklyBalancesAsync(request);
            
            if (response.Balances.Count > 0)
            {
                var balance = response.Balances[0];
                return new WeeklyBalanceDto
                {
                    WeekDefinitionId = balance.WeekDefinitionId,
                    WeekDisplayName = balance.WeekDisplayName,
                    LeftBalance = balance.LeftLegBalances,
                    RightBalance = balance.RightLegBalances,
                    MinBalance = Math.Min(balance.LeftLegBalances, balance.RightLegBalances),
                    BalanceCount = balance.TotalBalances,
                    CalculatedCommission = balance.WeeklyPoolContribution,
                    LeftCarryover = balance.LeftLegCarryover,
                    RightCarryover = balance.RightLegCarryover,
                    LeftNewMembers = balance.LeftLegNewMembers,
                    RightNewMembers = balance.RightLegNewMembers,
                    StartDate = balance.CalculatedAt?.ToDateTime().AddDays(-7) ?? DateTime.Now.AddDays(-7),
                    EndDate = balance.CalculatedAt?.ToDateTime() ?? DateTime.Now,
                    PackageId = balance.PackageId,
                    PackageTitle = balance.PackageTitle
                };
            }
            
            return CreateEmptyWeeklyBalance();
        }
        catch
        {
            return CreateEmptyWeeklyBalance();
        }
    }

    #region Helper Methods

    /// <summary>
    /// Get payouts that are eligible for withdrawal (all statuses except Withdrawn=3)
    /// </summary>
    public async Task<List<CommissionPayoutDto>> GetWithdrawablePayoutsAsync()
    {
        try
        {
            // Get all payouts that are not yet withdrawn
            // We'll get all and filter out Withdrawn (status=3) on client side
            var request = new GetMyCommissionPayoutsRequest
            {
                PageNumber = 1,
                PageSize = 100
                // No status filter - get all
            };
            
            var response = await _client.GetMyCommissionPayoutsAsync(request);
            
            // Filter: exclude already withdrawn (status=3) and withdrawal requested (status=2)
            return response.Payouts
                .Where(p => p.Status != 2 && p.Status != 3)
                .Select(p => new CommissionPayoutDto
                {
                    Id = p.Id,
                    WeekDefinitionId = p.WeekDefinitionId,
                    WeekDisplayName = p.WeekDisplayName,
                    BalancesEarned = p.BalancesEarned,
                    TotalAmount = p.TotalAmount,
                    AmountFormatted = p.AmountFormatted,
                    Status = p.Status,
                    DatePersian = p.DatePersian,
                    PackageId = p.PackageId,
                    PackageTitle = p.PackageTitle
                }).ToList();
        }
        catch
        {
            return new List<CommissionPayoutDto>();
        }
    }

    private static WeeklyBalanceDto CreateEmptyWeeklyBalance()
    {
        return new WeeklyBalanceDto
        {
            WeekDefinitionId = 0,
            WeekDisplayName = string.Empty,
            LeftBalance = 0,
            RightBalance = 0,
            MinBalance = 0,
            BalanceCount = 0,
            CalculatedCommission = 0,
            LeftCarryover = 0,
            RightCarryover = 0,
            StartDate = DateTime.MinValue,
            EndDate = DateTime.MinValue
        };
    }

    #endregion
}
