// EN: Command handlers for Inventory Service.
// VI: Command handlers cho Inventory Service.

using InventoryService.Domain.AggregatesModel.InventoryAggregate;
using MediatR;
using Microsoft.Extensions.Logging;

namespace InventoryService.API.Application.Commands;

/// <summary>
/// EN: Handler for StockInCommand.
/// VI: Handler cho StockInCommand.
/// </summary>
public class StockInCommandHandler : IRequestHandler<StockInCommand, Guid>
{
    private readonly IInventoryRepository _repository;
    private readonly ILogger<StockInCommandHandler> _logger;

    public StockInCommandHandler(
        IInventoryRepository repository,
        ILogger<StockInCommandHandler> logger)
    {
        _repository = repository;
        _logger = logger;
    }

    public async Task<Guid> Handle(StockInCommand request, CancellationToken ct)
    {
        // EN: Get or create inventory item
        // VI: Lấy hoặc tạo inventory item
        var item = await _repository.GetByProductAndShopAsync(
            request.ProductId, 
            request.ShopId, 
            ct);

        if (item == null)
        {
            item = new InventoryItem(request.ProductId, request.ShopId);
            await _repository.AddAsync(item, ct);
        }

        // EN: Perform stock in operation
        // VI: Thực hiện nhập kho
        item.StockIn(request.Amount, request.Notes, request.ReferenceId);

        await _repository.UnitOfWork.SaveChangesAsync(ct);

        _logger.LogInformation(
            "EN: Stock in completed / VI: Nhập kho hoàn thành - Product: {ProductId}, Shop: {ShopId}, Amount: {Amount}",
            request.ProductId, request.ShopId, request.Amount);

        return item.Id;
    }
}

/// <summary>
/// EN: Handler for StockOutCommand.
/// VI: Handler cho StockOutCommand.
/// </summary>
public class StockOutCommandHandler : IRequestHandler<StockOutCommand, bool>
{
    private readonly IInventoryRepository _repository;
    private readonly ILogger<StockOutCommandHandler> _logger;

    public StockOutCommandHandler(
        IInventoryRepository repository,
        ILogger<StockOutCommandHandler> logger)
    {
        _repository = repository;
        _logger = logger;
    }

    public async Task<bool> Handle(StockOutCommand request, CancellationToken ct)
    {
        var item = await _repository.GetByProductAndShopAsync(
            request.ProductId, 
            request.ShopId, 
            ct);

        if (item == null)
            return false;

        item.StockOut(request.Amount, request.Notes, request.ReferenceId);

        await _repository.UnitOfWork.SaveChangesAsync(ct);

        _logger.LogInformation(
            "EN: Stock out completed / VI: Xuất kho hoàn thành - Product: {ProductId}, Shop: {ShopId}, Amount: {Amount}",
            request.ProductId, request.ShopId, request.Amount);

        return true;
    }
}

/// <summary>
/// EN: Handler for ReserveStockCommand.
/// VI: Handler cho ReserveStockCommand.
/// </summary>
public class ReserveStockCommandHandler : IRequestHandler<ReserveStockCommand, bool>
{
    private readonly IInventoryRepository _repository;
    private readonly ILogger<ReserveStockCommandHandler> _logger;

    public ReserveStockCommandHandler(
        IInventoryRepository repository,
        ILogger<ReserveStockCommandHandler> logger)
    {
        _repository = repository;
        _logger = logger;
    }

    public async Task<bool> Handle(ReserveStockCommand request, CancellationToken ct)
    {
        var item = await _repository.GetByProductAndShopAsync(
            request.ProductId,
            request.ShopId,
            ct);

        if (item == null)
            return false;

        item.Reserve(request.Amount, request.OrderId);

        await _repository.UnitOfWork.SaveChangesAsync(ct);

        _logger.LogInformation(
            "EN: Stock reserved / VI: Stock đã đặt trước - Product: {ProductId}, Shop: {ShopId}, Amount: {Amount}, Order: {OrderId}",
            request.ProductId, request.ShopId, request.Amount, request.OrderId);

        return true;
    }
}

/// <summary>
/// EN: Handler for ReleaseReservationCommand.
/// VI: Handler cho ReleaseReservationCommand.
/// </summary>
public class ReleaseReservationCommandHandler : IRequestHandler<ReleaseReservationCommand, bool>
{
    private readonly IInventoryRepository _repository;
    private readonly ILogger<ReleaseReservationCommandHandler> _logger;

    public ReleaseReservationCommandHandler(
        IInventoryRepository repository,
        ILogger<ReleaseReservationCommandHandler> logger)
    {
        _repository = repository;
        _logger = logger;
    }

    public async Task<bool> Handle(ReleaseReservationCommand request, CancellationToken ct)
    {
        var item = await _repository.GetByProductAndShopAsync(
            request.ProductId,
            request.ShopId,
            ct);

        if (item == null)
            return false;

        item.ReleaseReservation(request.Amount, request.OrderId);

        await _repository.UnitOfWork.SaveChangesAsync(ct);

        _logger.LogInformation(
            "EN: Reservation released / VI: Đặt trước đã giải phóng - Product: {ProductId}, Shop: {ShopId}, Amount: {Amount}, Order: {OrderId}",
            request.ProductId, request.ShopId, request.Amount, request.OrderId);

        return true;
    }
}

/// <summary>
/// EN: Handler for AdjustStockCommand.
/// VI: Handler cho AdjustStockCommand.
/// </summary>
public class AdjustStockCommandHandler : IRequestHandler<AdjustStockCommand, bool>
{
    private readonly IInventoryRepository _repository;
    private readonly ILogger<AdjustStockCommandHandler> _logger;

    public AdjustStockCommandHandler(
        IInventoryRepository repository,
        ILogger<AdjustStockCommandHandler> logger)
    {
        _repository = repository;
        _logger = logger;
    }

    public async Task<bool> Handle(AdjustStockCommand request, CancellationToken ct)
    {
        var item = await _repository.GetByProductAndShopAsync(
            request.ProductId,
            request.ShopId,
            ct);

        if (item == null)
            return false;

        item.Adjust(request.NewQuantity, request.Notes);

        await _repository.UnitOfWork.SaveChangesAsync(ct);

        _logger.LogInformation(
            "EN: Stock adjusted / VI: Stock đã điều chỉnh - Product: {ProductId}, Shop: {ShopId}, NewQuantity: {NewQuantity}",
            request.ProductId, request.ShopId, request.NewQuantity);

        return true;
    }
}
