using Indotalent.ConfigBackEnd.Extensions;
using Indotalent.Infrastructure.Database;
using MediatR;
using Microsoft.EntityFrameworkCore;

namespace Indotalent.Features.Inventory.MovementReport.Cqrs;

public record GetInventoryMovementReportListDto
{
    public string? WarehouseName { get; init; }
    public string? ProductNumber { get; init; }
    public string? ProductName { get; init; }
    public double AdjPlus { get; init; }
    public double AdjMinus { get; init; }
    public double Count { get; init; }
    public double Do { get; init; }
    public double Gr { get; init; }
    public double Prn { get; init; }
    public double Scrp { get; init; }
    public double Srn { get; init; }
    public double ToIn { get; init; }
    public double ToOut { get; init; }
    public double GrandTotal => AdjPlus + AdjMinus + Count + Do + Gr + Prn + Scrp + Srn + ToIn + ToOut;
}

public record GetInventoryMovementReportListQuery() : IRequest<List<GetInventoryMovementReportListDto>>;

public class GetInventoryMovementReportListHandler : IRequestHandler<GetInventoryMovementReportListQuery, List<GetInventoryMovementReportListDto>>
{
    private readonly AppDbContext _context;

    public GetInventoryMovementReportListHandler(AppDbContext context)
    {
        _context = context;
    }

    public async Task<List<GetInventoryMovementReportListDto>> Handle(GetInventoryMovementReportListQuery request, CancellationToken cancellationToken)
    {
        var transactions = await _context.InventoryTransaction
            .AsNoTracking()
            .Include(x => x.Warehouse)
            .Include(x => x.Product)
            .Where(x =>
                x.Product!.Physical == true &&
                x.Warehouse!.SystemWarehouse == false &&
                x.Status == Data.Enums.InventoryTransactionStatus.Confirmed
            )
            .ToListAsync(cancellationToken);

        var results = transactions
            .GroupBy(x => new { x.WarehouseId, x.ProductId })
            .Select(group => new GetInventoryMovementReportListDto
            {
                WarehouseName = group.Max(x => x.Warehouse?.Name),
                ProductNumber = group.Max(x => x.Product?.AutoNumber),
                ProductName = group.Max(x => x.Product?.Name),
                AdjPlus = group.Where(x => x.ModuleCode == "ADJ+").Sum(x => x.Movement ?? 0),
                AdjMinus = group.Where(x => x.ModuleCode == "ADJ-").Sum(x => x.Movement ?? 0),
                Count = group.Where(x => x.ModuleCode == "COUNT").Sum(x => x.Movement ?? 0),
                Do = group.Where(x => x.ModuleCode == "DO").Sum(x => x.Movement ?? 0),
                Gr = group.Where(x => x.ModuleCode == "GR").Sum(x => x.Movement ?? 0),
                Prn = group.Where(x => x.ModuleCode == "PRN").Sum(x => x.Movement ?? 0),
                Scrp = group.Where(x => x.ModuleCode == "SCRP").Sum(x => x.Movement ?? 0),
                Srn = group.Where(x => x.ModuleCode == "SRN").Sum(x => x.Movement ?? 0),
                ToIn = group.Where(x => x.ModuleCode == "TO-IN").Sum(x => x.Movement ?? 0),
                ToOut = group.Where(x => x.ModuleCode == "TO-OUT").Sum(x => x.Movement ?? 0)
            })
            .OrderBy(x => x.WarehouseName)
            .ThenBy(x => x.ProductName)
            .ToList();

        return results;
    }
}