using InventoryService.Domain.AggregatesModel.InventoryAggregate;
using InventoryService.Domain.SeedWork;
using Microsoft.EntityFrameworkCore;

namespace InventoryService.Infrastructure.Repositories;

public class InventoryRepository : IInventoryRepository
{
    private readonly InventoryContext _context;
    public IUnitOfWork UnitOfWork => _context;

    public InventoryRepository(InventoryContext context)
    {
        _context = context ?? throw new ArgumentNullException(nameof(context));
    }

    public InventoryItem Add(InventoryItem item)
    {
        return _context.InventoryItems.Add(item).Entity;
    }

    public void Update(InventoryItem item)
    {
        _context.Entry(item).State = EntityState.Modified;
    }

    public async Task<InventoryItem?> GetByIdAsync(Guid id, CancellationToken cancellationToken = default)
    {
        return await _context.InventoryItems.FirstOrDefaultAsync(i => i.Id == id, cancellationToken);
    }

    public async Task<InventoryItem?> GetByProductAndShopAsync(Guid productId, Guid shopId, CancellationToken cancellationToken = default)
    {
        return await _context.InventoryItems
            .FirstOrDefaultAsync(i => i.ProductId == productId && i.ShopId == shopId, cancellationToken);
    }

    public async Task<InventoryItem?> GetByProductIdAsync(Guid productId, Guid shopId, CancellationToken cancellationToken = default)
    {
        return await GetByProductAndShopAsync(productId, shopId, cancellationToken);
    }

    public async Task<(IReadOnlyList<InventoryItem> Items, int Total)> GetByShopAsync(
        Guid shopId, 
        int skip = 0, 
        int take = 50, 
        CancellationToken cancellationToken = default)
    {
        var query = _context.InventoryItems.Where(i => i.ShopId == shopId);
        
        var total = await query.CountAsync(cancellationToken);
        var items = await query
            .OrderBy(i => i.ProductId)
            .Skip(skip)
            .Take(take)
            .ToListAsync(cancellationToken);

        return (items, total);
    }

    public async Task<IEnumerable<InventoryItem>> GetByShopIdAsync(Guid shopId, CancellationToken cancellationToken = default)
    {
        return await _context.InventoryItems
            .Where(i => i.ShopId == shopId)
            .ToListAsync(cancellationToken);
    }

    public async Task<(IReadOnlyList<InventoryTransaction> Transactions, int Total)> GetTransactionsAsync(
        Guid inventoryItemId, 
        int skip = 0, 
        int take = 50, 
        CancellationToken cancellationToken = default)
    {
        var item = await _context.InventoryItems
            .Include(i => i.Transactions)
            .FirstOrDefaultAsync(i => i.Id == inventoryItemId, cancellationToken);

        if (item == null)
            return (new List<InventoryTransaction>(), 0);

        var total = item.Transactions.Count;
        var transactions = item.Transactions
            .OrderByDescending(t => t.CreatedAt)
            .Skip(skip)
            .Take(take)
            .ToList();

        return (transactions, total);
    }

    public async Task<(IReadOnlyList<InventoryItem> Items, int Total)> GetLowStockItemsAsync(
        Guid? shopId = null, 
        int skip = 0, 
        int take = 50, 
        CancellationToken cancellationToken = default)
    {
        var query = _context.InventoryItems
            .Where(i => i.AvailableQuantity <= i.ReorderLevel);

        if (shopId.HasValue)
            query = query.Where(i => i.ShopId == shopId.Value);

        var total = await query.CountAsync(cancellationToken);
        var items = await query
            .OrderBy(i => i.AvailableQuantity)
            .Skip(skip)
            .Take(take)
            .ToListAsync(cancellationToken);

        return (items, total);
    }

    public async Task<InventoryItem> AddAsync(InventoryItem item, CancellationToken cancellationToken = default)
    {
        var entity = await _context.InventoryItems.AddAsync(item, cancellationToken);
        return entity.Entity;
    }
}
