using FruitBank.Common.Entities;
using Nop.Core.Domain.Orders;
using Nop.Core.Domain.Payments;
using Nop.Data;
using Nop.Plugin.Misc.FruitBankPlugin.Domains.DataLayer;

namespace Nop.Plugin.Misc.FruitBankPlugin.Services;

public class CustomerCreditService : ICustomerCreditService
{
    private readonly CustomerCreditDbTable _customerCreditDbTable;
    private readonly IRepository<Order> _orderRepository;

    public CustomerCreditService(
        CustomerCreditDbTable customerCreditDbTable,
        IRepository<Order> orderRepository)
    {
        _customerCreditDbTable = customerCreditDbTable;
        _orderRepository = orderRepository;
    }

    public Task<CustomerCredit?> GetByCustomerIdAsync(int customerId)
        => _customerCreditDbTable.GetByCustomerIdAsync(customerId);

    public async Task SaveAsync(CustomerCredit entity)
    {
        entity.UpdatedOnUtc = DateTime.UtcNow;

        if (entity.Id <= 0)
        {
            entity.CreatedOnUtc = DateTime.UtcNow;
            await _customerCreditDbTable.InsertAsync(entity);
        }
        else
        {
            await _customerCreditDbTable.UpdateAsync(entity);
        }
    }

    public Task DeleteAsync(CustomerCredit entity)
        => _customerCreditDbTable.DeleteAsync(entity);

    public async Task<decimal> GetOutstandingBalanceAsync(int customerId)
    {
        return await _orderRepository.Table
            .Where(o =>
                o.CustomerId == customerId &&
                o.OrderStatusId != (int)OrderStatus.Cancelled &&
                (o.PaymentStatusId == (int)PaymentStatus.Pending ||
                 o.PaymentStatusId == (int)PaymentStatus.PartiallyRefunded))
            .SumAsync(o => (decimal?)o.OrderTotal) ?? 0m;
    }

    public async Task<decimal?> GetRemainingCreditAsync(int customerId)
    {
        var credit = await GetByCustomerIdAsync(customerId);
        if (credit == null) return null;

        var outstanding = await GetOutstandingBalanceAsync(customerId);
        return credit.CreditLimit - outstanding;
    }

    public async Task<bool> IsOrderAllowedAsync(int customerId, decimal newOrderTotal)
    {
        var credit = await GetByCustomerIdAsync(customerId);
        if (credit == null) return true;

        var outstanding = await GetOutstandingBalanceAsync(customerId);
        return outstanding + newOrderTotal <= credit.CreditLimit;
    }
}
