using DateTimeConverterCL; using CMSMicroservice.Protobuf.Protos.UserWallet; using CMSMicroservice.Protobuf.Protos.UserWalletChangeLog; using Google.Protobuf.WellKnownTypes; namespace FrontOffice.Main.Utilities; public record WalletBalances(long CreditBalance, long DiscountBalance, long NetworkBalance); public record WalletTransaction( string Date, long CreditChange, long CreditBalance, long NetworkChange, long NetworkBalance, long DiscountChange, long DiscountBalance, string Channel, string Description ); public record WalletWithdrawal(long Id, long WeekDefinitionId, string WeekDisplayName, long Amount, int Status, int? Method, string? Iban, string Created); public enum WithdrawalMethodClient { Cash = 0, Diamond = 1 } public record WithdrawalSettings(long MinWithdrawalAmount); public record MagicWalletStatus( int WalletMode, long MagicTotalDeposited, long MagicTotalCredited, long MagicMaxDeposit, long MagicRemainingDeposit, long Balance, DateTime? MagicActivatedAt ); public class WalletService { private readonly CMSMicroservice.Protobuf.Protos.UserWallet.UserWalletContract.UserWalletContractClient _client; public WalletService(CMSMicroservice.Protobuf.Protos.UserWallet.UserWalletContract.UserWalletContractClient client) { _client = client; } public async Task GetBalancesAsync() { try { var response = await _client.GetCustomerWalletAsync(new Empty()); return new WalletBalances(response.Balance, response.DiscountBalance, response.NetworkBalance); } catch { // Return zero balances if backend is unavailable return new WalletBalances(0, 0, 0); } } public async Task> GetTransactionsAsync(long? referenceId = null, bool? isIncrease = null) { try { var request = new GetCustomerWalletChangeLogRequest(); if (referenceId.HasValue) { request.ReferenceId = referenceId.Value; } if (isIncrease.HasValue) { request.IsIncrease = isIncrease.Value; } var response = await _client.GetCustomerWalletChangeLogAsync(request); return response.Models .Select(log => new WalletTransaction( ResolveTransactionDate(log), log.ChangeValue, log.CurrentBalance, log.ChangeNerworkValue, log.CurrentNetworkBalance, log.ChangeDiscountValue, log.CurrentDiscountBalance, log.RefrenceId?.ToString() ?? "-", ResolveDescription(log) )) .OrderByDescending(t => t.Date) .ToList(); } catch { // Return empty list if backend is unavailable return new List(); } } private static string ResolveTransactionDate(CustomerWalletChangeLogModel model) { if (model.CreatedAt is not null) { try { var utcDate = model.CreatedAt.ToDateTime(); return utcDate.ToLocalTime().MiladiToJalaliWithTime(); } catch { // ignore conversion issues and fall through to default } } return DateTime.Now.MiladiToJalaliWithTime(); } private static string ResolveDescription(CustomerWalletChangeLogModel model) { var parts = new List(); if (model.ChangeValue != 0) parts.Add(model.ChangeValue > 0 ? "شارژ عادی" : "برداشت عادی"); if (model.ChangeNerworkValue != 0) parts.Add(model.ChangeNerworkValue > 0 ? "دریافت شبکه" : "برداشت شبکه"); if (model.ChangeDiscountValue != 0) parts.Add(model.ChangeDiscountValue > 0 ? "شارژ اعتباری" : "خرید اعتباری"); return parts.Count > 0 ? string.Join(" | ", parts) : "تراکنش کیف پول"; } public async Task RequestWithdrawalAsync(long payoutId, WithdrawalMethodClient method, string? iban) { var request = new CustomerWithdrawBalanceRequest { PayoutId = payoutId, WithdrawalMethod = (int)method }; if (!string.IsNullOrWhiteSpace(iban)) { request.IbanNumber = iban; } try { await _client.CustomerWithdrawBalanceAsync(request); return true; } catch (Grpc.Core.RpcException ex) { throw new InvalidOperationException(ex.Status.Detail ?? "خطا در ثبت برداشت", ex); } } public async Task> GetWithdrawalsAsync(int? status = null) { try { var request = new GetCustomerWithdrawalsRequest(); if (status.HasValue) { request.Status = status.Value; } var response = await _client.GetCustomerWithdrawalsAsync(request); return response.Models .Select(m => new WalletWithdrawal( m.Id, m.WeekDefinitionId, m.WeekDisplayName, m.TotalAmount, m.Status, m.WithdrawalMethod, m.IbanNumber, m.Created?.ToDateTime().MiladiToJalaliWithTime() ?? "-")) .ToList(); } catch { return new List(); } } public async Task GetWithdrawalSettingsAsync() { try { var response = await _client.GetCustomerWithdrawalSettingsAsync(new Empty()); return new WithdrawalSettings(response.MinWithdrawalAmount); } catch { // Return default settings if backend is unavailable return new WithdrawalSettings(0); } } // ============= Magic Wallet ============= public async Task GetMagicWalletStatusAsync() { try { var response = await _client.GetMagicWalletStatusAsync(new Empty()); DateTime? activatedAt = response.MagicActivatedAt != null ? response.MagicActivatedAt.ToDateTime().ToLocalTime() : null; return new MagicWalletStatus( response.WalletMode, response.MagicTotalDeposited, response.MagicTotalCredited, response.MagicMaxDeposit, response.MagicRemainingDeposit, response.Balance, activatedAt ); } catch { return new MagicWalletStatus(0, 0, 0, 0, 0, 0, null); } } public async Task<(bool Success, string? GatewayUrl, string? Error)> InitiateMagicChargeAsync(long amount) { try { var response = await _client.InitiateMagicChargeAsync(new InitiateMagicChargeRequest { Amount = amount }); if (response.IsSuccess) return (true, response.GatewayUrl, null); return (false, null, response.ErrorMessage); } catch (Grpc.Core.RpcException ex) { return (false, null, ex.Status.Detail ?? "خطا در ارتباط با سرور"); } } public int GetWalletMode() { try { var response = _client.GetCustomerWallet(new Empty()); return response.WalletMode; } catch { return 0; } } }