using CashLineERP.Contracts.Finance;

namespace CashLineERP.Application.Finance;

public sealed class AccountingPeriodService : IAccountingPeriodService
{
    private readonly IAccountingPeriodRepository _repository;

    public AccountingPeriodService(IAccountingPeriodRepository repository)
    {
        _repository = repository;
    }

    public IReadOnlyCollection<AccountingPeriodResponse> GetPeriods() =>
        _repository.GetPeriods().Select(Map).ToArray();

    public AccountingPeriodCloseReadinessResponse GetCloseReadiness(long accountingPeriodId)
    {
        var readiness = _repository.GetCloseReadiness(accountingPeriodId);
        return Map(readiness);
    }

    public AccountingPeriodMonthEndReviewResponse GetMonthEndReview(long accountingPeriodId)
    {
        var review = _repository.GetMonthEndReview(accountingPeriodId);
        return new AccountingPeriodMonthEndReviewResponse(
            review.AccountingPeriodId,
            review.PeriodCode,
            Map(review.CloseReadiness),
            review.CloseJournalClassSummaries
                .Select(summary => new AccountingPeriodMonthEndJournalClassSummaryResponse(
                    summary.JournalClassCode,
                    summary.DraftCount,
                    summary.SubmittedCount,
                    summary.ApprovedCount,
                    summary.PostedCount,
                    summary.PostedAmount))
                .ToArray(),
            review.OpenItems
                .Select(item => new AccountingPeriodMonthEndOpenItemResponse(
                    item.ModuleCode,
                    item.DocumentType,
                    item.DocumentId,
                    item.DocumentNumber,
                    item.BusinessDate,
                    item.StatusCode,
                    item.ValueAmount,
                    item.Notes))
                .ToArray());
    }

    public AccountingPeriodResponse MarkReadyToClose(long accountingPeriodId, long actorUserId) =>
        Map(_repository.MarkReadyToClose(accountingPeriodId, actorUserId));

    public AccountingPeriodResponse Close(long accountingPeriodId, long actorUserId) =>
        Map(_repository.Close(accountingPeriodId, actorUserId));

    private static AccountingPeriodResponse Map(AccountingPeriodView period) =>
        new(
            period.AccountingPeriodId,
            period.PeriodCode,
            period.StartDate,
            period.EndDate,
            period.CloseStatusCode,
            period.IsYearEnd,
            period.ReadyForCloseAtUtc,
            period.ClosedAtUtc);

    private static AccountingPeriodCloseReadinessResponse Map(AccountingPeriodCloseReadinessView readiness) =>
        new(
            readiness.AccountingPeriodId,
            readiness.PeriodCode,
            readiness.CloseStatusCode,
            readiness.PostedGeneralLedgerBatchCount,
            readiness.BankStatementCount,
            readiness.ReconciledStatementLineCount,
            readiness.UnreconciledStatementLineCount,
            readiness.ExceptionReconciliationItemCount,
            readiness.PendingEtaInvoiceCount,
            readiness.OpenArInvoiceCount,
            readiness.OpenArReceiptCount,
            readiness.OpenApBillCount,
            readiness.OpenApPaymentCount,
            readiness.OpenInventoryAdjustmentCount,
            readiness.OpenStockCountCount,
            readiness.OpenWarehouseTransferCount,
            readiness.OpenInventoryStatusControlCount,
            readiness.OpenCloseJournalCount,
            readiness.OpenFxRevaluationCount,
            readiness.PostedAccrualCloseJournalCount,
            readiness.PostedAdjustmentCloseJournalCount,
            readiness.IsReadyToClose,
            readiness.BlockingReasons);
}
