using CashLineERP.Contracts.Finance;

namespace CashLineERP.Application.Finance;

public sealed class CustomerStatementService : ICustomerStatementService
{
    private readonly ICustomerStatementRepository _repository;

    public CustomerStatementService(ICustomerStatementRepository repository)
    {
        _repository = repository;
    }

    public IReadOnlyCollection<CustomerStatementSummaryResponse> GetStatements(long? customerId = null) =>
        _repository.GetStatements(customerId)
            .Select(Map)
            .ToArray();

    public CustomerStatementResponse? GetStatement(long customerStatementId)
    {
        var statement = _repository.GetStatement(customerStatementId);
        return statement is null ? null : Map(statement);
    }

    public CustomerStatementResponse GenerateStatement(long actorUserId, CreateCustomerStatementRequest request) =>
        Map(_repository.GenerateStatement(
            actorUserId,
            new CreateCustomerStatementCommand(
                request.CustomerId,
                request.DateFrom,
                request.DateTo,
                request.CurrencyCode)));

    public IReadOnlyCollection<CustomerStatementDeliveryLogResponse> GetDeliveryLogs(long customerStatementId) =>
        _repository.GetDeliveryLogs(customerStatementId)
            .Select(Map)
            .ToArray();

    public CustomerStatementDeliveryLogResponse RecordDelivery(long customerStatementId, long actorUserId, RecordCustomerStatementDeliveryRequest request) =>
        Map(_repository.RecordDelivery(
            customerStatementId,
            actorUserId,
            new RecordCustomerStatementDeliveryCommand(
                request.DeliveredAtUtc ?? DateTime.UtcNow,
                request.ChannelCode,
                request.RecipientAddress,
                request.DeliveryStatusCode,
                request.Notes)));

    private static CustomerStatementSummaryResponse Map(CustomerStatementSummaryView statement) =>
        new(
            statement.CustomerStatementId,
            statement.StatementNumber,
            statement.CustomerId,
            statement.CustomerCode,
            statement.CustomerName,
            statement.DateFrom,
            statement.DateTo,
            statement.CurrencyCode,
            statement.OpeningBalanceAmount,
            statement.TotalChargeAmount,
            statement.TotalSettlementAmount,
            statement.ClosingBalanceAmount,
            statement.OpenInvoiceAmount,
            statement.OverdueInvoiceAmount,
            statement.LineCount,
            statement.DeliveryLogCount,
            statement.GeneratedAtUtc,
            statement.GeneratedByUserId);

    private static CustomerStatementResponse Map(CustomerStatementDetailView statement) =>
        new(
            statement.CustomerStatementId,
            statement.StatementNumber,
            statement.CustomerId,
            statement.CustomerCode,
            statement.CustomerName,
            statement.DateFrom,
            statement.DateTo,
            statement.CurrencyCode,
            statement.OpeningBalanceAmount,
            statement.TotalChargeAmount,
            statement.TotalSettlementAmount,
            statement.ClosingBalanceAmount,
            statement.OpenInvoiceAmount,
            statement.OverdueInvoiceAmount,
            statement.GeneratedAtUtc,
            statement.GeneratedByUserId,
            statement.Lines.Select(Map).ToArray(),
            statement.DeliveryLogs.Select(Map).ToArray());

    private static CustomerStatementLineResponse Map(CustomerStatementLineView line) =>
        new(
            line.EntryType,
            line.DocumentType,
            line.DocumentId,
            line.DocumentNumber,
            line.BusinessDate,
            line.DueDate,
            line.CurrencyCode,
            line.ChargeAmount,
            line.SettlementAmount,
            line.RunningBalanceAmount,
            line.StatusCode,
            line.ReferenceText);

    private static CustomerStatementDeliveryLogResponse Map(CustomerStatementDeliveryLogView log) =>
        new(
            log.CustomerStatementDeliveryLogId,
            log.CustomerStatementId,
            log.DeliveredAtUtc,
            log.ChannelCode,
            log.RecipientAddress,
            log.DeliveryStatusCode,
            log.Notes,
            log.CreatedByUserId,
            log.CreatedAtUtc);
}
