using CashLineERP.Contracts.Finance;

namespace CashLineERP.Application.Finance;

public sealed class AccountsReceivableInvoiceService : IAccountsReceivableInvoiceService
{
    private readonly IAccountsReceivableInvoiceRepository _repository;

    public AccountsReceivableInvoiceService(IAccountsReceivableInvoiceRepository repository)
    {
        _repository = repository;
    }

    public IReadOnlyCollection<AccountsReceivableInvoiceResponse> GetInvoices() =>
        _repository.GetInvoices().Select(Map).ToArray();

    public AccountsReceivableInvoiceResponse? GetInvoice(long accountsReceivableInvoiceId)
    {
        var invoice = _repository.GetInvoice(accountsReceivableInvoiceId);
        return invoice is null ? null : Map(invoice);
    }

    public AccountsReceivableInvoiceResponse CreateInvoice(CreateAccountsReceivableInvoiceRequest request)
    {
        var invoice = _repository.Create(new CreateAccountsReceivableInvoiceCommand(
            request.CustomerId,
            request.SalesOrderId,
            request.DispatchOrderId,
            request.InvoiceType,
            request.InvoiceDate,
            request.TaxDate,
            request.DueDate,
            request.CurrencyCode,
            request.Lines.Select(line => new CreateAccountsReceivableInvoiceLineCommand(
                line.SalesOrderLineId,
                line.ItemId,
                line.QuantityInvoiced,
                line.UnitOfMeasureCode,
                line.UnitPrice,
                line.TaxCode)).ToArray()));

        return Map(invoice);
    }

    public AccountsReceivableInvoiceResponse SubmitInvoice(long accountsReceivableInvoiceId, long actorUserId) =>
        Map(_repository.Submit(accountsReceivableInvoiceId, actorUserId));

    public AccountsReceivableInvoiceResponse ApproveInvoice(long accountsReceivableInvoiceId, long actorUserId) =>
        Map(_repository.Approve(accountsReceivableInvoiceId, actorUserId));

    public AccountsReceivableInvoiceResponse PostInvoice(long accountsReceivableInvoiceId, long actorUserId) =>
        Map(_repository.Post(accountsReceivableInvoiceId, actorUserId));

    private static AccountsReceivableInvoiceResponse Map(AccountsReceivableInvoiceDetailView invoice) =>
        new(
            invoice.AccountsReceivableInvoiceId,
            invoice.InvoiceNumber,
            invoice.CustomerId,
            invoice.SalesOrderId,
            invoice.DispatchOrderId,
            invoice.InvoiceType,
            invoice.InvoiceDate,
            invoice.TaxDate,
            invoice.DueDate,
            invoice.CurrencyCode,
            invoice.StatusCode,
            invoice.SubtotalAmount,
            invoice.TaxAmount,
            invoice.TotalAmount,
            invoice.EtaUuid,
            invoice.EtaStatus,
            invoice.GeneralLedgerBatchId,
            invoice.Lines.Select(line => new AccountsReceivableInvoiceLineResponse(
                line.AccountsReceivableInvoiceLineId,
                line.LineNumber,
                line.SalesOrderLineId,
                line.ItemId,
                line.QuantityInvoiced,
                line.UnitOfMeasureCode,
                line.UnitPrice,
                line.TaxCode,
                line.LineNetAmount,
                line.LineTaxAmount,
                line.LineTotalAmount)).ToArray());
}
