using CashLineERP.Contracts.Finance;

namespace CashLineERP.Application.Finance;

public sealed class SupplierStatementService : ISupplierStatementService
{
    private readonly ISupplierStatementRepository _repository;

    public SupplierStatementService(ISupplierStatementRepository repository)
    {
        _repository = repository;
    }

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

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

    public SupplierStatementResponse GenerateStatement(long actorUserId, CreateSupplierStatementRequest request) =>
        Map(_repository.GenerateStatement(
            actorUserId,
            new CreateSupplierStatementCommand(
                request.SupplierId,
                request.DateFrom,
                request.DateTo,
                request.CurrencyCode)));

    public IReadOnlyCollection<SupplierStatementDeliveryLogResponse> GetDeliveryLogs(long supplierStatementId) =>
        _repository.GetDeliveryLogs(supplierStatementId)
            .Select(Map)
            .ToArray();

    public SupplierStatementDeliveryLogResponse RecordDelivery(long supplierStatementId, long actorUserId, RecordSupplierStatementDeliveryRequest request) =>
        Map(_repository.RecordDelivery(
            supplierStatementId,
            actorUserId,
            new RecordSupplierStatementDeliveryCommand(
                request.DeliveredAtUtc ?? DateTime.UtcNow,
                request.ChannelCode,
                request.RecipientAddress,
                request.DeliveryStatusCode,
                request.Notes)));

    public SupplierStatementDeliveryLogResponse AcknowledgeDelivery(long supplierStatementDeliveryLogId, long actorUserId, AcknowledgeSupplierStatementDeliveryRequest request) =>
        Map(_repository.AcknowledgeDelivery(
            supplierStatementDeliveryLogId,
            actorUserId,
            new AcknowledgeSupplierStatementDeliveryCommand(
                request.AcknowledgmentStatusCode,
                request.Notes)));

    private static SupplierStatementSummaryResponse Map(SupplierStatementSummaryView statement) =>
        new(
            statement.SupplierStatementId,
            statement.StatementNumber,
            statement.SupplierId,
            statement.SupplierCode,
            statement.SupplierName,
            statement.DateFrom,
            statement.DateTo,
            statement.CurrencyCode,
            statement.OpeningBalanceAmount,
            statement.TotalChargeAmount,
            statement.TotalSettlementAmount,
            statement.ClosingBalanceAmount,
            statement.OpenPayableAmount,
            statement.OverduePayableAmount,
            statement.LineCount,
            statement.DeliveryLogCount,
            statement.GeneratedAtUtc,
            statement.GeneratedByUserId);

    private static SupplierStatementResponse Map(SupplierStatementDetailView statement) =>
        new(
            statement.SupplierStatementId,
            statement.StatementNumber,
            statement.SupplierId,
            statement.SupplierCode,
            statement.SupplierName,
            statement.DateFrom,
            statement.DateTo,
            statement.CurrencyCode,
            statement.OpeningBalanceAmount,
            statement.TotalChargeAmount,
            statement.TotalSettlementAmount,
            statement.ClosingBalanceAmount,
            statement.OpenPayableAmount,
            statement.OverduePayableAmount,
            statement.GeneratedAtUtc,
            statement.GeneratedByUserId,
            statement.Lines.Select(line => new SupplierStatementLineResponse(
                line.EntryType,
                line.DocumentType,
                line.DocumentId,
                line.DocumentNumber,
                line.BusinessDate,
                line.DueDate,
                line.CurrencyCode,
                line.ChargeAmount,
                line.SettlementAmount,
                line.RunningBalanceAmount,
                line.StatusCode,
                line.ReferenceText)).ToArray());

    private static SupplierStatementDeliveryLogResponse Map(SupplierStatementDeliveryLogView log) =>
        new(
            log.SupplierStatementDeliveryLogId,
            log.SupplierStatementId,
            log.DeliveredAtUtc,
            log.ChannelCode,
            log.RecipientAddress,
            log.DeliveryStatusCode,
            log.Notes,
            log.AcknowledgmentStatusCode,
            log.AcknowledgedAtUtc,
            log.AcknowledgedByUserId,
            log.CreatedByUserId,
            log.CreatedAtUtc);
}
