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

namespace Indotalent.Features.Sales.CreditNote.Cqrs;

public class CreditNoteItemResponse
{
    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 GetCreditNoteByIdResponse
{
    public string? Id { get; set; }
    public string? AutoNumber { get; set; }
    public DateTime? CreditNoteDate { get; set; }
    public Data.Enums.CreditNoteStatus CreditNoteStatus { get; set; }
    public string? Description { get; set; }
    public string? SalesReturnId { get; set; }
    public string? SalesReturnNumber { get; set; }
    public string? CustomerName { get; set; }
    public string? CustomerStreet { get; set; }
    public string? CustomerCity { 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<CreditNoteItemResponse> Items { get; set; } = new();
}

public record GetCreditNoteByIdQuery(string Id) : IRequest<GetCreditNoteByIdResponse?>;

public class GetCreditNoteByIdHandler : IRequestHandler<GetCreditNoteByIdQuery, GetCreditNoteByIdResponse?>
{
    private readonly AppDbContext _context;
    public GetCreditNoteByIdHandler(AppDbContext context) => _context = context;

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

        var creditNote = await _context.CreditNote
            .AsNoTracking()
            .Include(x => x.SalesReturn)
                .ThenInclude(sr => sr!.DeliveryOrder)
                    .ThenInclude(do_ => do_!.SalesOrder)
                        .ThenInclude(so => so!.Customer)
            .Include(x => x.SalesReturn)
                .ThenInclude(sr => sr!.DeliveryOrder)
                    .ThenInclude(do_ => do_!.SalesOrder)
                        .ThenInclude(so => so!.Tax)
            .FirstOrDefaultAsync(x => x.Id == request.Id, cancellationToken);

        if (creditNote == null) return null;

        var salesOrder = creditNote.SalesReturn?.DeliveryOrder?.SalesOrder;
        var taxRate = salesOrder?.Tax?.PercentageValue ?? 0;

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

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

        foreach (var trans in transactions)
        {
            var soItem = await _context.SalesOrderItem
                .AsNoTracking()
                .FirstOrDefaultAsync(x => x.SalesOrderId == salesOrder!.Id && x.ProductId == trans.ProductId, cancellationToken);

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

            items.Add(new CreditNoteItemResponse
            {
                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 GetCreditNoteByIdResponse
        {
            Id = creditNote.Id,
            AutoNumber = creditNote.AutoNumber,
            CreditNoteDate = creditNote.CreditNoteDate,
            CreditNoteStatus = creditNote.CreditNoteStatus,
            Description = creditNote.Description,
            SalesReturnId = creditNote.SalesReturnId,
            SalesReturnNumber = creditNote.SalesReturn?.AutoNumber,
            CustomerName = salesOrder?.Customer?.Name,
            CustomerStreet = salesOrder?.Customer?.Street,
            CustomerCity = salesOrder?.Customer?.City,
            CompanyName = company?.Name,
            CompanyStreet = company?.StreetAddress,
            CompanyCity = company?.City,
            CurrencySymbol = company?.Currency?.Symbol ?? "IDR",
            BeforeTaxAmount = subTotal,
            TaxAmount = taxAmount,
            AfterTaxAmount = subTotal + taxAmount,
            CreatedAt = creditNote.CreatedAt,
            CreatedBy = creditNote.CreatedBy,
            UpdatedAt = creditNote.UpdatedAt,
            UpdatedBy = creditNote.UpdatedBy,
            Items = items
        };
    }
}