using DateTimeConverterCL;
using CMSMicroservice.Protobuf.Protos.UserWallet;
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,
    int PurchaseCycleCount,
    double MagicMultiplier = 2.5,
    long MagicMaxCredit = 2_500_000_000
);

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<WalletBalances> 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<List<WalletTransaction>> GetTransactionsAsync(long? referenceId = null, bool? isIncrease = null)
    {
        try
        {
            var request = new GetCustomerWalletHistoryRequest();
            if (referenceId.HasValue)
            {
                request.ReferenceId = referenceId.Value;
            }
            if (isIncrease.HasValue)
            {
                request.IsIncrease = isIncrease.Value;
            }
            var response = await _client.GetCustomerWalletHistoryAsync(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<WalletTransaction>();
        }
    }

    private static string ResolveTransactionDate(CustomerWalletHistoryModel 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(CustomerWalletHistoryModel model)
    {
        var parts = new List<string>();
        
        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<bool> 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<List<WalletWithdrawal>> 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<WalletWithdrawal>();
        }
    }

    public async Task<WithdrawalSettings> 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<MagicWalletStatus> 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,
                response.PurchaseCycleCount,
                response.MagicMultiplier > 0 ? response.MagicMultiplier : 2.5,
                response.MagicMaxCredit > 0 ? response.MagicMaxCredit : 2_500_000_000
            );
        }
        catch
        {
            return new MagicWalletStatus(0, 0, 0, 0, 0, 0, null, 0);
        }
    }

    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 async Task<(bool Success, string? GatewayUrl, string? Error)> InitiateDiscountChargeAsync(long amount)
    {
        try
        {
            var response = await _client.InitiateDiscountChargeAsync(new InitiateDiscountChargeRequest
            {
                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 async Task<(bool Success, string? GatewayUrl, string? Error)> InitiateCreditChargeAsync(long amount)
    {
        try
        {
            var response = await _client.InitiateCreditChargeAsync(new InitiateCreditChargeRequest
            {
                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 ?? "خطا در ارتباط با سرور");
        }
    }

    // ============= Wallet Verify Methods =============

    public async Task<(bool Success, string Message)> VerifyMagicChargeAsync(string authority, string status)
    {
        try
        {
            var response = await _client.VerifyMagicChargeAsync(new VerifyWalletChargeRequest
            {
                Authority = authority,
                Status = status
            });

            return (response.Success, response.Message);
        }
        catch (Grpc.Core.RpcException ex)
        {
            return (false, ex.Status.Detail ?? "خطا در بررسی وضعیت پرداخت");
        }
    }

    public async Task<(bool Success, string Message)> VerifyDiscountChargeAsync(string authority, string status)
    {
        try
        {
            var response = await _client.VerifyDiscountChargeAsync(new VerifyWalletChargeRequest
            {
                Authority = authority,
                Status = status
            });

            return (response.Success, response.Message);
        }
        catch (Grpc.Core.RpcException ex)
        {
            return (false, ex.Status.Detail ?? "خطا در بررسی وضعیت پرداخت");
        }
    }

    public async Task<(bool Success, string Message)> VerifyCreditChargeAsync(string authority, string status)
    {
        try
        {
            var response = await _client.VerifyCreditChargeAsync(new VerifyWalletChargeRequest
            {
                Authority = authority,
                Status = status
            });

            return (response.Success, response.Message);
        }
        catch (Grpc.Core.RpcException ex)
        {
            return (false, ex.Status.Detail ?? "خطا در بررسی وضعیت پرداخت");
        }
    }

    public int GetWalletMode()
    {
        try
        {
            var response = _client.GetCustomerWallet(new Empty());
            return response.WalletMode;
        }
        catch
        {
            return 0;
        }
    }
}
