using ERPCore.Domain.Entities;
using ERPCore.Dtos.Common;
using ERPCore.Dtos.Procurement;
using ERPCore.Dtos.Stock;
using ERPCore.Repositories.Interfaces;
using ERPCore.Services.Interfaces;
using ERPCore.System.Errors;
using Microsoft.EntityFrameworkCore;

namespace ERPCore.Services;

/// <summary>
/// Reorder alerts are a query, not a stored entity (docs/10 C.9): available stock
/// (from the FIFO layers) is compared to <see cref="ItemReorder"/> policy on read.
/// </summary>
public sealed class ReorderService : IReorderService
{
    private readonly IRepository<ItemReorder> _reorders;
    private readonly IStockService _stock;
    private readonly IRequisitionService _requisitions;

    public ReorderService(IRepository<ItemReorder> reorders, IStockService stock, IRequisitionService requisitions)
    {
        _reorders = reorders;
        _stock = stock;
        _requisitions = requisitions;
    }

    public async Task<PagedResponse<ReorderAlertDto>> GetAlertsAsync(int? warehouseId, PageQuery query, CancellationToken ct = default)
    {
        var q = _reorders.Query().AsNoTracking();
        if (warehouseId is not null) q = q.Where(r => r.WarehouseId == warehouseId);
        var policies = await q.OrderBy(r => r.ItemId).ToListAsync(ct);

        var alerts = new List<ReorderAlertDto>();
        foreach (var p in policies)
        {
            var available = (await _stock.GetOnHandAsync(p.ItemId, p.WarehouseId, ct)).Available;
            if (available <= p.ReorderPoint)
                alerts.Add(new ReorderAlertDto(p.ItemId, p.WarehouseId, available, p.ReorderPoint, p.ReorderQty, p.ReorderQty));
        }

        var page = alerts.Skip(query.Skip).Take(query.PageSize).ToList();
        return PagedResponse<ReorderAlertDto>.Create(page, query.Page, query.PageSize, alerts.Count);
    }

    public async Task<RequisitionDto> CreateSuggestedRequisitionAsync(int itemId, int warehouseId, CancellationToken ct = default)
    {
        var policy = await _reorders.Query().AsNoTracking()
            .FirstOrDefaultAsync(r => r.ItemId == itemId && r.WarehouseId == warehouseId, ct)
            ?? throw new DomainException(ErrorCodes.Validation,
                $"No reorder policy for item {itemId} at warehouse {warehouseId}.", 422);

        return await _requisitions.CreateAsync(new CreateRequisitionRequest
        {
            Lines = [new CreateRequisitionLineInput { ItemId = itemId, Qty = policy.ReorderQty }]
        }, ct);
    }
}
