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

namespace Indotalent.Features.Purchase.DebitNote.Cqrs;

public class DebitNoteItemResponse
{
    public string? Id { get; set; }
    public string? ProductId { get; set; }
    public string? ProductName { get; set; }
    public decimal UnitPrice { get; set; }
    public double Quantity { get; set; }
    public decimal Total { get; set; }
}

public class GetDebitNoteByIdResponse
{
    public string? Id { get; set; }
    public string? AutoNumber { get; set; }
    public DateTime? DebitNoteDate { get; set; }
    public Data.Enums.DebitNoteStatus DebitNoteStatus { get; set; }
    public string? Description { get; set; }
    public string? PurchaseReturnId { get; set; }
    public string? PurchaseReturnNumber { get; set; }
    public string? VendorName { get; set; }
    public string? VendorStreet { get; set; }
    public string? VendorCity { get; set; }
    public string? CompanyName { get; set; }
    public string? CompanyStreet { get; set; }
    public string? CompanyCity { get; set; }
    public string? CurrencySymbol { get; set; }
    public decimal BeforeTaxAmount { get; set; }
    public decimal TaxAmount { get; set; }
    public decimal AfterTaxAmount { get; set; }
    public DateTimeOffset? CreatedAt { get; set; }
    public string? CreatedBy { get; set; }
    public DateTimeOffset? UpdatedAt { get; set; }
    public string? UpdatedBy { get; set; }
    public List<DebitNoteItemResponse> Items { get; set; } = new();
}

public record GetDebitNoteByIdQuery(string Id) : IRequest<GetDebitNoteByIdResponse?>;

public class GetDebitNoteByIdHandler : IRequestHandler<GetDebitNoteByIdQuery, GetDebitNoteByIdResponse?>
{
    private readonly AppDbContext _context;
    public GetDebitNoteByIdHandler(AppDbContext context) => _context = context;

    public async Task<GetDebitNoteByIdResponse?> Handle(GetDebitNoteByIdQuery request, CancellationToken cancellationToken)
    {
        var company = await _context.Company
            .AsNoTracking()
            .Include(x => x.Currency)
            .OrderByDescending(x => x.IsDefault)
            .FirstOrDefaultAsync(cancellationToken);

        var debitNote = await _context.DebitNote
            .AsNoTracking()
            .Include(x => x.PurchaseReturn)
                .ThenInclude(pr => pr!.GoodsReceive)
                    .ThenInclude(gr => gr!.PurchaseOrder)
                        .ThenInclude(po => po!.Vendor)
            .Include(x => x.PurchaseReturn)
                .ThenInclude(pr => pr!.GoodsReceive)
                    .ThenInclude(gr => gr!.PurchaseOrder)
                        .ThenInclude(po => po!.Tax)
            .FirstOrDefaultAsync(x => x.Id == request.Id, cancellationToken);

        if (debitNote == null) return null;

        var purchaseOrder = debitNote.PurchaseReturn?.GoodsReceive?.PurchaseOrder;
        var taxRate = purchaseOrder?.Tax?.PercentageValue ?? 0;

        var transactions = await _context.InventoryTransaction
            .AsNoTracking()
            .Include(x => x.Product)
            .Where(x => x.ModuleId == debitNote.PurchaseReturnId && x.ModuleName == nameof(Data.Entities.PurchaseReturn))
            .ToListAsync(cancellationToken);

        var items = new List<DebitNoteItemResponse>();
        decimal subTotal = 0;

        foreach (var trans in transactions)
        {
            var poItem = await _context.PurchaseOrderItem
                .AsNoTracking()
                .FirstOrDefaultAsync(x => x.PurchaseOrderId == purchaseOrder!.Id && x.ProductId == trans.ProductId, cancellationToken);

            var unitPrice = poItem?.UnitPrice ?? 0;
            var qty = Math.Abs(trans.Movement ?? 0);
            var total = unitPrice * (decimal)qty;

            items.Add(new DebitNoteItemResponse
            {
                Id = trans.Id,
                ProductId = trans.ProductId,
                ProductName = trans.Product?.Name,
                UnitPrice = unitPrice,
                Quantity = qty,
                Total = total
            });

            subTotal += total;
        }

        var taxAmount = subTotal * (decimal)(taxRate / 100);

        return new GetDebitNoteByIdResponse
        {
            Id = debitNote.Id,
            AutoNumber = debitNote.AutoNumber,
            DebitNoteDate = debitNote.DebitNoteDate,
            DebitNoteStatus = debitNote.DebitNoteStatus,
            Description = debitNote.Description,
            PurchaseReturnId = debitNote.PurchaseReturnId,
            PurchaseReturnNumber = debitNote.PurchaseReturn?.AutoNumber,
            VendorName = purchaseOrder?.Vendor?.Name,
            VendorStreet = purchaseOrder?.Vendor?.Street,
            VendorCity = purchaseOrder?.Vendor?.City,
            CompanyName = company?.Name,
            CompanyStreet = company?.StreetAddress,
            CompanyCity = company?.City,
            CurrencySymbol = company?.Currency?.Symbol ?? "IDR",
            BeforeTaxAmount = subTotal,
            TaxAmount = taxAmount,
            AfterTaxAmount = subTotal + taxAmount,
            CreatedAt = debitNote.CreatedAt,
            CreatedBy = debitNote.CreatedBy,
            UpdatedAt = debitNote.UpdatedAt,
            UpdatedBy = debitNote.UpdatedBy,
            Items = items
        };
    }
}