// EN: Main controller for Inventory operations.
// VI: Controller chính cho các thao tác Inventory.

using Asp.Versioning;
using InventoryService.API.Application.Commands;
using InventoryService.API.Application.DTOs;
using InventoryService.API.Application.Queries;
using MediatR;
using Microsoft.AspNetCore.Mvc;
using Swashbuckle.AspNetCore.Annotations;

namespace InventoryService.API.Controllers;

/// <summary>
/// EN: Controller for inventory operations.
/// VI: Controller cho các thao tác inventory.
/// </summary>
[ApiController]
[ApiVersion("1.0")]
[Route("api/v{version:apiVersion}/inventory")]
[SwaggerTag("Inventory Management - Stock operations, reservations, and tracking")]
public class InventoryController : ControllerBase
{
    private readonly IMediator _mediator;
    private readonly ILogger<InventoryController> _logger;

    public InventoryController(
        IMediator mediator,
        ILogger<InventoryController> logger)
    {
        _mediator = mediator;
        _logger = logger;
    }

    /// <summary>
    /// EN: Get inventory by shop.
    /// VI: Lấy inventory theo shop.
    /// </summary>
    [HttpGet]
    [SwaggerOperation(Summary = "Get inventory by shop with pagination")]
    [SwaggerResponse(200, "Inventory items retrieved successfully")]
    [SwaggerResponse(400, "Invalid request")]
    public async Task<ActionResult<ApiResponse<PagedResult<InventoryItemDto>>>> GetInventory(
        [FromQuery] Guid shopId,
        [FromQuery] int skip = 0,
        [FromQuery] int take = 50,
        CancellationToken ct = default)
    {
        if (shopId == Guid.Empty)
            return BadRequest(ApiResponse<PagedResult<InventoryItemDto>>.Fail("Shop ID is required"));

        var query = new GetInventoryByShopQuery(shopId, skip, take);
        var result = await _mediator.Send(query, ct);

        return Ok(ApiResponse<PagedResult<InventoryItemDto>>.Ok(result));
    }

    /// <summary>
    /// EN: Get stock level for specific product and shop.
    /// VI: Lấy mức tồn kho cho product và shop cụ thể.
    /// </summary>
    [HttpGet("{productId:guid}")]
    [SwaggerOperation(Summary = "Get stock level by product ID and shop ID")]
    [SwaggerResponse(200, "Stock level retrieved successfully")]
    [SwaggerResponse(404, "Inventory item not found")]
    public async Task<ActionResult<ApiResponse<InventoryItemDto>>> GetStockLevel(
        Guid productId,
        [FromQuery] Guid shopId,
        CancellationToken ct = default)
    {
        var query = new GetStockLevelQuery(productId, shopId);
        var result = await _mediator.Send(query, ct);

        if (result == null)
            return NotFound(ApiResponse<InventoryItemDto>.Fail("Inventory item not found"));

        return Ok(ApiResponse<InventoryItemDto>.Ok(result));
    }

    /// <summary>
    /// EN: Stock in operation (add inventory).
    /// VI: Thao tác nhập kho (thêm inventory).
    /// </summary>
    [HttpPost("stock-in")]
    [SwaggerOperation(Summary = "Add stock to inventory")]
    [SwaggerResponse(200, "Stock added successfully")]
    [SwaggerResponse(400, "Invalid request")]
    public async Task<ActionResult<ApiResponse<Guid>>> StockIn(
        [FromBody] StockInRequest request,
        CancellationToken ct = default)
    {
        try
        {
            var command = new StockInCommand(
                request.ProductId,
                request.ShopId,
                request.Amount,
                request.Notes,
                request.ReferenceId);

            var inventoryItemId = await _mediator.Send(command, ct);

            return Ok(ApiResponse<Guid>.Ok(inventoryItemId));
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error performing stock in");
            return BadRequest(ApiResponse<Guid>.Fail(ex.Message));
        }
    }

    /// <summary>
    /// EN: Stock out operation (remove inventory).
    /// VI: Thao tác xuất kho (giảm inventory).
    /// </summary>
    [HttpPost("stock-out")]
    [SwaggerOperation(Summary = "Remove stock from inventory")]
    [SwaggerResponse(200, "Stock removed successfully")]
    [SwaggerResponse(400, "Invalid request or insufficient stock")]
    [SwaggerResponse(404, "Inventory item not found")]
    public async Task<ActionResult<ApiResponse<bool>>> StockOut(
        [FromBody] StockOutRequest request,
        CancellationToken ct = default)
    {
        try
        {
            var command = new StockOutCommand(
                request.ProductId,
                request.ShopId,
                request.Amount,
                request.Notes,
                request.ReferenceId);

            var result = await _mediator.Send(command, ct);

            if (!result)
                return NotFound(ApiResponse<bool>.Fail("Inventory item not found"));

            return Ok(ApiResponse<bool>.Ok(result));
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error performing stock out");
            return BadRequest(ApiResponse<bool>.Fail(ex.Message));
        }
    }

    /// <summary>
    /// EN: Reserve stock for order.
    /// VI: Đặt trước stock cho order.
    /// </summary>
    [HttpPost("reserve")]
    [SwaggerOperation(Summary = "Reserve stock for order")]
    [SwaggerResponse(200, "Stock reserved successfully")]
    [SwaggerResponse(400, "Invalid request or insufficient available stock")]
    [SwaggerResponse(404, "Inventory item not found")]
    public async Task<ActionResult<ApiResponse<bool>>> ReserveStock(
        [FromBody] ReserveStockRequest request,
        CancellationToken ct = default)
    {
        try
        {
            var command = new ReserveStockCommand(
                request.ProductId,
                request.ShopId,
                request.Amount,
                request.OrderId);

            var result = await _mediator.Send(command, ct);

            if (!result)
                return NotFound(ApiResponse<bool>.Fail("Inventory item not found"));

            return Ok(ApiResponse<bool>.Ok(result));
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error reserving stock");
            return BadRequest(ApiResponse<bool>.Fail(ex.Message));
        }
    }

    /// <summary>
    /// EN: Release stock reservation.
    /// VI: Giải phóng đặt trước stock.
    /// </summary>
    [HttpPost("release")]
    [SwaggerOperation(Summary = "Release stock reservation")]
    [SwaggerResponse(200, "Reservation released successfully")]
    [SwaggerResponse(400, "Invalid request")]
    [SwaggerResponse(404, "Inventory item not found")]
    public async Task<ActionResult<ApiResponse<bool>>> ReleaseReservation(
        [FromBody] ReleaseReservationRequest request,
        CancellationToken ct = default)
    {
        try
        {
            var command = new ReleaseReservationCommand(
                request.ProductId,
                request.ShopId,
                request.Amount,
                request.OrderId);

            var result = await _mediator.Send(command, ct);

            if (!result)
                return NotFound(ApiResponse<bool>.Fail("Inventory item not found"));

            return Ok(ApiResponse<bool>.Ok(result));
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error releasing reservation");
            return BadRequest(ApiResponse<bool>.Fail(ex.Message));
        }
    }

    /// <summary>
    /// EN: Adjust stock (manual correction).
    /// VI: Điều chỉnh stock (sửa thủ công).
    /// </summary>
    [HttpPost("adjust")]
    [SwaggerOperation(Summary = "Manually adjust stock quantity")]
    [SwaggerResponse(200, "Stock adjusted successfully")]
    [SwaggerResponse(400, "Invalid request")]
    [SwaggerResponse(404, "Inventory item not found")]
    public async Task<ActionResult<ApiResponse<bool>>> AdjustStock(
        [FromBody] AdjustStockRequest request,
        CancellationToken ct = default)
    {
        try
        {
            var command = new AdjustStockCommand(
                request.ProductId,
                request.ShopId,
                request.NewQuantity,
                request.Notes);

            var result = await _mediator.Send(command, ct);

            if (!result)
                return NotFound(ApiResponse<bool>.Fail("Inventory item not found"));

            return Ok(ApiResponse<bool>.Ok(result));
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error adjusting stock");
            return BadRequest(ApiResponse<bool>.Fail(ex.Message));
        }
    }

    /// <summary>
    /// EN: Get transaction history for inventory item.
    /// VI: Lấy lịch sử transactions cho inventory item.
    /// </summary>
    [HttpGet("transactions")]
    [SwaggerOperation(Summary = "Get transaction history")]
    [SwaggerResponse(200, "Transactions retrieved successfully")]
    [SwaggerResponse(400, "Invalid request")]
    public async Task<ActionResult<ApiResponse<PagedResult<InventoryTransactionDto>>>> GetTransactions(
        [FromQuery] Guid inventoryItemId,
        [FromQuery] int skip = 0,
        [FromQuery] int take = 50,
        CancellationToken ct = default)
    {
        if (inventoryItemId == Guid.Empty)
            return BadRequest(ApiResponse<PagedResult<InventoryTransactionDto>>.Fail("Inventory item ID is required"));

        var query = new GetTransactionsQuery(inventoryItemId, skip, take);
        var result = await _mediator.Send(query, ct);

        return Ok(ApiResponse<PagedResult<InventoryTransactionDto>>.Ok(result));
    }

    /// <summary>
    /// EN: Get low stock items.
    /// VI: Lấy các items stock thấp.
    /// </summary>
    [HttpGet("low-stock")]
    [SwaggerOperation(Summary = "Get items with stock at or below reorder level")]
    [SwaggerResponse(200, "Low stock items retrieved successfully")]
    public async Task<ActionResult<ApiResponse<PagedResult<InventoryItemDto>>>> GetLowStockItems(
        [FromQuery] Guid? shopId = null,
        [FromQuery] int skip = 0,
        [FromQuery] int take = 50,
        CancellationToken ct = default)
    {
        var query = new GetLowStockItemsQuery(shopId, skip, take);
        var result = await _mediator.Send(query, ct);

        return Ok(ApiResponse<PagedResult<InventoryItemDto>>.Ok(result));
    }
}
