using CashLineERP.Contracts.Finance;

namespace CashLineERP.Application.Finance;

public sealed class CollectionsWorkbenchService : ICollectionsWorkbenchService
{
    private readonly ICollectionsWorkbenchRepository _repository;

    public CollectionsWorkbenchService(ICollectionsWorkbenchRepository repository)
    {
        _repository = repository;
    }

    public CollectionsWorkbenchSummaryResponse GetSummary(DateOnly? asOfDate = null)
    {
        var normalizedAsOfDate = asOfDate ?? DateOnly.FromDateTime(DateTime.UtcNow.Date);
        var summary = _repository.GetSummary(normalizedAsOfDate);
        return new CollectionsWorkbenchSummaryResponse(
            summary.AsOfDate,
            summary.OverdueInvoiceCount,
            summary.OverdueCustomerCount,
            summary.TotalOutstandingAmount,
            summary.ActionRequiredCount,
            summary.PromiseToPayCount,
            summary.BrokenPromiseCount);
    }

    public IReadOnlyCollection<CollectionsQueueItemResponse> GetQueue(
        DateOnly? asOfDate = null,
        long? customerId = null,
        string? currencyCode = null,
        bool actionRequiredOnly = false)
    {
        var normalizedAsOfDate = asOfDate ?? DateOnly.FromDateTime(DateTime.UtcNow.Date);
        return _repository.GetQueue(normalizedAsOfDate, customerId, currencyCode, actionRequiredOnly)
            .Select(item => new CollectionsQueueItemResponse(
                item.AccountsReceivableInvoiceId,
                item.InvoiceNumber,
                item.CustomerId,
                item.CustomerCode,
                item.CustomerName,
                item.BranchId,
                item.InvoiceDate,
                item.DueDate,
                item.CurrencyCode,
                item.InvoiceTotalAmount,
                item.OutstandingAmount,
                item.OverdueDays,
                item.AgingBucketCode,
                item.LastFollowUpActionDate,
                item.LastFollowUpActionTypeCode,
                item.LastFollowUpOutcomeCode,
                item.PromiseToPayDate,
                item.NextFollowUpDate,
                item.ActionRequired,
                item.Summary))
            .ToArray();
    }

    public IReadOnlyCollection<CollectionsFollowUpActionResponse> GetFollowUpActions(long accountsReceivableInvoiceId) =>
        _repository.GetFollowUpActions(accountsReceivableInvoiceId)
            .Select(Map)
            .ToArray();

    public CollectionsCustomerSummaryResponse GetCustomerSummary(long customerId, DateOnly? asOfDate = null, string? currencyCode = null)
    {
        var normalizedAsOfDate = asOfDate ?? DateOnly.FromDateTime(DateTime.UtcNow.Date);
        var summary = _repository.GetCustomerSummary(customerId, normalizedAsOfDate, currencyCode);
        return new CollectionsCustomerSummaryResponse(
            summary.AsOfDate,
            summary.CustomerId,
            summary.CustomerCode,
            summary.CustomerName,
            summary.CurrencyCode,
            summary.OverdueInvoiceCount,
            summary.TotalOutstandingAmount,
            summary.ActionRequiredCount,
            summary.PromiseToPayCount,
            summary.BrokenPromiseCount,
            summary.NextFollowUpDueCount,
            summary.Queue.Select(item => new CollectionsQueueItemResponse(
                item.AccountsReceivableInvoiceId,
                item.InvoiceNumber,
                item.CustomerId,
                item.CustomerCode,
                item.CustomerName,
                item.BranchId,
                item.InvoiceDate,
                item.DueDate,
                item.CurrencyCode,
                item.InvoiceTotalAmount,
                item.OutstandingAmount,
                item.OverdueDays,
                item.AgingBucketCode,
                item.LastFollowUpActionDate,
                item.LastFollowUpActionTypeCode,
                item.LastFollowUpOutcomeCode,
                item.PromiseToPayDate,
                item.NextFollowUpDate,
                item.ActionRequired,
                item.Summary)).ToArray(),
            summary.RecentActions.Select(Map).ToArray());
    }

    public CollectionsFollowUpActionResponse RecordFollowUp(long accountsReceivableInvoiceId, long actorUserId, RecordCollectionsFollowUpRequest request) =>
        Map(_repository.RecordFollowUp(
            accountsReceivableInvoiceId,
            actorUserId,
            new RecordCollectionsFollowUpCommand(
                request.ActionDate,
                request.ActionTypeCode,
                request.OutcomeCode,
                request.PromiseToPayDate,
                request.NextFollowUpDate,
                request.Notes)));

    private static CollectionsFollowUpActionResponse Map(CollectionsFollowUpActionView action) =>
        new(
            action.CollectionsFollowUpActionId,
            action.AccountsReceivableInvoiceId,
            action.CustomerId,
            action.ActionDate,
            action.ActionTypeCode,
            action.OutcomeCode,
            action.PromiseToPayDate,
            action.NextFollowUpDate,
            action.Notes,
            action.CreatedByUserId,
            action.CreatedAtUtc);
}
