using CashLineERP.Contracts.Identity;
using CashLineERP.Contracts.External;
using CashLineERP.Contracts.Finance;
using CashLineERP.Contracts.Parties;
using CashLineERP.Contracts.Tax;
using CashLineERP.Application.External;
using CashLineERP.Application.Finance;
using CashLineERP.Application.Parties;
using CashLineERP.Application.Customers;
using CashLineERP.Application.Suppliers;
using CashLineERP.Application.Tax;

namespace CashLineERP.Application.Identity;

public sealed class AccountingOfficeService : IAccountingOfficeService
{
    private const string ViewWorkspaceActionCode = "VIEW_CLIENT_WORKSPACE";
    private const string ViewSubmissionPostureActionCode = "VIEW_SUBMISSION_POSTURE";
    private const string UploadComplianceDocumentActionCode = "UPLOAD_COMPLIANCE_DOCUMENT";
    private const string SubmitEtaInvoiceActionCode = "SUBMIT_ETA_INVOICE";
    private const string RecordStatementDeliveryActionCode = "RECORD_STATEMENT_DELIVERY";
    private const string AcknowledgeStatementDeliveryActionCode = "ACKNOWLEDGE_STATEMENT_DELIVERY";
    private const string RetryStatementDeliveryActionCode = "RETRY_STATEMENT_DELIVERY";
    private const string GenerateStatementActionCode = "GENERATE_STATEMENT";
    private const string ExportClientReportActionCode = "EXPORT_CLIENT_REPORT";

    private readonly IAccountingOfficeClientAssignmentRepository _assignmentRepository;
    private readonly IAccountingOfficeAuditRepository _auditRepository;
    private readonly IPartyOnboardingService _partyOnboardingService;
    private readonly IExternalPortalService _externalPortalService;
    private readonly ISupplierProfileService _supplierProfileService;
    private readonly ICustomerProfileService _customerProfileService;
    private readonly IOnboardingCaseService _onboardingCaseService;
    private readonly IEtaComplianceService _etaComplianceService;
    private readonly ICustomerStatementService _customerStatementService;
    private readonly ISupplierStatementService _supplierStatementService;

    public AccountingOfficeService(
        IAccountingOfficeClientAssignmentRepository assignmentRepository,
        IAccountingOfficeAuditRepository auditRepository,
        IPartyOnboardingService partyOnboardingService,
        IExternalPortalService externalPortalService,
        ISupplierProfileService supplierProfileService,
        ICustomerProfileService customerProfileService,
        IOnboardingCaseService onboardingCaseService,
        IEtaComplianceService etaComplianceService,
        ICustomerStatementService customerStatementService,
        ISupplierStatementService supplierStatementService)
    {
        _assignmentRepository = assignmentRepository;
        _auditRepository = auditRepository;
        _partyOnboardingService = partyOnboardingService;
        _externalPortalService = externalPortalService;
        _supplierProfileService = supplierProfileService;
        _customerProfileService = customerProfileService;
        _onboardingCaseService = onboardingCaseService;
        _etaComplianceService = etaComplianceService;
        _customerStatementService = customerStatementService;
        _supplierStatementService = supplierStatementService;
    }

    public IReadOnlyCollection<AccountingOfficeClientAssignmentResponse> GetAssignments(long accountingOfficeUserId) =>
        _assignmentRepository.GetAssignments(accountingOfficeUserId).Select(Map).ToArray();

    public AccountingOfficeClientAssignmentResponse AssignClient(long accountingOfficeUserId, AssignAccountingOfficeClientRequest request, long actorUserId) =>
        Map(_assignmentRepository.Assign(accountingOfficeUserId, request.PartyId, actorUserId));

    public void RemoveClient(long accountingOfficeUserId, long partyId, long actorUserId) =>
        _assignmentRepository.Revoke(accountingOfficeUserId, partyId, actorUserId);

    public IReadOnlyCollection<AccountingOfficeClientAssignmentResponse> GetCurrentUserClients(long accountingOfficeUserId) =>
        GetAssignments(accountingOfficeUserId);

    public AccountingOfficeClientWorkspaceResponse GetCurrentUserClientWorkspace(long accountingOfficeUserId, long partyId)
    {
        var workspace = BuildClientWorkspace(accountingOfficeUserId, partyId);
        _auditRepository.RecordAction(accountingOfficeUserId, partyId, ViewWorkspaceActionCode, "Opened delegated client workspace.");
        return workspace;
    }

    public AccountingOfficeClientSubmissionPostureResponse GetCurrentUserClientSubmissionPosture(long accountingOfficeUserId, long partyId)
    {
        var workspace = BuildClientWorkspace(accountingOfficeUserId, partyId);
        var onboardingCases = _onboardingCaseService.GetCases(submittedByUserId: accountingOfficeUserId)
            .Where(item => item.BusinessPartyId == partyId)
            .ToArray();

        var pendingOnboardingCaseCount = onboardingCases.Count(item =>
            string.Equals(item.CaseStatusCode, "SUBMITTED", StringComparison.OrdinalIgnoreCase)
            || string.Equals(item.CaseStatusCode, "UNDER_REVIEW", StringComparison.OrdinalIgnoreCase)
            || string.Equals(item.CaseStatusCode, "PENDING_APPROVAL", StringComparison.OrdinalIgnoreCase)
            || string.Equals(item.CaseStatusCode, "ON_HOLD", StringComparison.OrdinalIgnoreCase)
            || string.Equals(item.CaseStatusCode, "RETURNED_FOR_REWORK", StringComparison.OrdinalIgnoreCase));
        var approvedOnboardingCaseCount = onboardingCases.Count(item =>
            string.Equals(item.CaseStatusCode, "APPROVED", StringComparison.OrdinalIgnoreCase)
            || string.Equals(item.CaseStatusCode, "ACTIVATED", StringComparison.OrdinalIgnoreCase));

        var etaReadinessCode = ResolveEtaReadinessCode(workspace, pendingOnboardingCaseCount);
        var readinessSummary = ResolveSubmissionReadinessSummary(workspace, etaReadinessCode, pendingOnboardingCaseCount);

        _auditRepository.RecordAction(accountingOfficeUserId, partyId, ViewSubmissionPostureActionCode, readinessSummary);

        return new AccountingOfficeClientSubmissionPostureResponse(
            workspace.Client,
            workspace.SupplierProfile is not null,
            workspace.CustomerProfile is not null,
            workspace.Invoices.Count,
            workspace.Payments.Count,
            workspace.ComplianceDocuments.Count,
            pendingOnboardingCaseCount,
            approvedOnboardingCaseCount,
            etaReadinessCode,
            readinessSummary);
    }

    public BusinessPartyComplianceDocumentResponse RecordCurrentUserClientComplianceDocument(long accountingOfficeUserId, long partyId, RecordBusinessPartyComplianceDocumentRequest request)
    {
        EnsureAssigned(accountingOfficeUserId, partyId);
        var document = _partyOnboardingService.RecordComplianceDocument(accountingOfficeUserId, partyId, request);
        _auditRepository.RecordAction(
            accountingOfficeUserId,
            partyId,
            UploadComplianceDocumentActionCode,
            $"Uploaded {document.DocumentType} document {document.FileName}.");
        return document;
    }

    public EtaSubmissionValidationPackResponse? GetCurrentUserClientInvoiceEtaValidationPack(long accountingOfficeUserId, long partyId, long invoiceId)
    {
        ResolveAssignedClientInvoice(accountingOfficeUserId, partyId, invoiceId);
        return _etaComplianceService.GetSubmissionValidationPack(invoiceId);
    }

    public IReadOnlyCollection<EtaSubmissionLogResponse> GetCurrentUserClientInvoiceEtaSubmissionLogs(long accountingOfficeUserId, long partyId, long invoiceId)
    {
        ResolveAssignedClientInvoice(accountingOfficeUserId, partyId, invoiceId);
        return _etaComplianceService.GetSubmissionLogs(invoiceId);
    }

    public EtaSubmissionLogResponse SubmitCurrentUserClientInvoiceToEta(long accountingOfficeUserId, long partyId, long invoiceId, SubmitInvoiceToEtaRequest request)
    {
        var invoice = ResolveAssignedClientInvoice(accountingOfficeUserId, partyId, invoiceId);
        var submission = _etaComplianceService.SubmitInvoice(invoiceId, request with
        {
            ActorUserId = accountingOfficeUserId
        });
        _auditRepository.RecordAction(
            accountingOfficeUserId,
            partyId,
            SubmitEtaInvoiceActionCode,
            $"Submitted ETA invoice {invoice.InvoiceNumber} ({invoice.InvoiceId}) for client {invoice.ReferenceNumber ?? invoice.InvoiceNumber}.");
        return submission;
    }

    public IReadOnlyCollection<ExternalStatementDocumentResponse> GetCurrentUserClientStatementDocuments(long accountingOfficeUserId, long partyId)
    {
        EnsureAssigned(accountingOfficeUserId, partyId);
        return _externalPortalService.GetStatementDocuments(partyId);
    }

    public IReadOnlyCollection<ExternalStatementDeliveryLogResponse> GetCurrentUserClientStatementDeliveryLogs(long accountingOfficeUserId, long partyId, long statementId)
    {
        ResolveAssignedClientStatement(accountingOfficeUserId, partyId, statementId);
        return _externalPortalService.GetStatementDeliveryLogs(partyId, statementId);
    }

    public ExternalStatementDeliveryLogResponse RecordCurrentUserClientStatementDelivery(long accountingOfficeUserId, long partyId, long statementId, RecordAccountingOfficeClientStatementDeliveryRequest request)
    {
        var statement = ResolveAssignedClientStatement(accountingOfficeUserId, partyId, statementId);
        ExternalStatementDeliveryLogResponse deliveryLog;
        if (string.Equals(statement.StatementType, "SUPPLIER_STATEMENT", StringComparison.OrdinalIgnoreCase))
        {
            var supplierLog = _supplierStatementService.RecordDelivery(
                statementId,
                accountingOfficeUserId,
                new RecordSupplierStatementDeliveryRequest(
                    request.DeliveredAtUtc,
                    request.ChannelCode,
                    request.RecipientAddress,
                    request.DeliveryStatusCode,
                    request.Notes));

            deliveryLog = new ExternalStatementDeliveryLogResponse(
                "SUPPLIER_STATEMENT",
                statementId,
                supplierLog.SupplierStatementDeliveryLogId,
                supplierLog.DeliveredAtUtc,
                supplierLog.ChannelCode,
                supplierLog.RecipientAddress,
                supplierLog.DeliveryStatusCode,
                supplierLog.AcknowledgmentStatusCode,
                supplierLog.AcknowledgedAtUtc,
                supplierLog.AcknowledgedByUserId,
                supplierLog.Notes);
        }
        else if (string.Equals(statement.StatementType, "CUSTOMER_STATEMENT", StringComparison.OrdinalIgnoreCase))
        {
            var customerLog = _customerStatementService.RecordDelivery(
                statementId,
                accountingOfficeUserId,
                new RecordCustomerStatementDeliveryRequest(
                    request.DeliveredAtUtc,
                    request.ChannelCode,
                    request.RecipientAddress,
                    request.DeliveryStatusCode,
                    request.Notes));

            deliveryLog = new ExternalStatementDeliveryLogResponse(
                "CUSTOMER_STATEMENT",
                statementId,
                customerLog.CustomerStatementDeliveryLogId,
                customerLog.DeliveredAtUtc,
                customerLog.ChannelCode,
                customerLog.RecipientAddress,
                customerLog.DeliveryStatusCode,
                null,
                null,
                null,
                customerLog.Notes);
        }
        else
        {
            throw new InvalidOperationException($"Statement type '{statement.StatementType}' is not supported for delegated delivery recording.");
        }

        _auditRepository.RecordAction(
            accountingOfficeUserId,
            partyId,
            RecordStatementDeliveryActionCode,
            $"Recorded {deliveryLog.StatementType} delivery for statement {statement.StatementNumber} ({statement.StatementId}) via {deliveryLog.ChannelCode} with status {deliveryLog.DeliveryStatusCode}.");
        return deliveryLog;
    }

    public ExternalStatementDeliveryLogResponse AcknowledgeCurrentUserClientSupplierStatementDelivery(long accountingOfficeUserId, long partyId, long statementId, long deliveryLogId, AcknowledgeAccountingOfficeClientStatementDeliveryRequest request)
    {
        var statement = ResolveAssignedClientStatement(accountingOfficeUserId, partyId, statementId);
        if (!string.Equals(statement.StatementType, "SUPPLIER_STATEMENT", StringComparison.OrdinalIgnoreCase))
        {
            throw new InvalidOperationException("Only supplier statement delivery logs support acknowledgment in the delegated accounting office lane.");
        }

        var deliveryLog = _externalPortalService.GetStatementDeliveryLogs(partyId, statementId)
            .SingleOrDefault(item => item.DeliveryLogId == deliveryLogId)
            ?? throw new InvalidOperationException("The requested statement delivery log is not available for the assigned client statement.");

        var acknowledgedLog = _supplierStatementService.AcknowledgeDelivery(
            deliveryLogId,
            accountingOfficeUserId,
            new AcknowledgeSupplierStatementDeliveryRequest(
                request.AcknowledgmentStatusCode,
                request.Notes));

        var response = new ExternalStatementDeliveryLogResponse(
            "SUPPLIER_STATEMENT",
            statementId,
            acknowledgedLog.SupplierStatementDeliveryLogId,
            acknowledgedLog.DeliveredAtUtc,
            acknowledgedLog.ChannelCode,
            acknowledgedLog.RecipientAddress,
            acknowledgedLog.DeliveryStatusCode,
            acknowledgedLog.AcknowledgmentStatusCode,
            acknowledgedLog.AcknowledgedAtUtc,
            acknowledgedLog.AcknowledgedByUserId,
            acknowledgedLog.Notes);

        _auditRepository.RecordAction(
            accountingOfficeUserId,
            partyId,
            AcknowledgeStatementDeliveryActionCode,
            $"Acknowledged supplier statement delivery log {deliveryLogId} for statement {statement.StatementNumber} ({statement.StatementId}) with status {response.AcknowledgmentStatusCode ?? "N/A"}.");
        return response;
    }

    public ExternalStatementDeliveryLogResponse RetryCurrentUserClientStatementDelivery(long accountingOfficeUserId, long partyId, long statementId, long deliveryLogId, RetryAccountingOfficeClientStatementDeliveryRequest request)
    {
        var statement = ResolveAssignedClientStatement(accountingOfficeUserId, partyId, statementId);
        var existingLog = _externalPortalService.GetStatementDeliveryLogs(partyId, statementId)
            .SingleOrDefault(item => item.DeliveryLogId == deliveryLogId)
            ?? throw new InvalidOperationException("The requested statement delivery log is not available for the assigned client statement.");

        var channelCode = string.IsNullOrWhiteSpace(request.ChannelCode) ? existingLog.ChannelCode : request.ChannelCode!;
        var recipientAddress = string.IsNullOrWhiteSpace(request.RecipientAddress) ? existingLog.RecipientAddress : request.RecipientAddress;
        var deliveryStatusCode = string.IsNullOrWhiteSpace(request.DeliveryStatusCode) ? "SENT" : request.DeliveryStatusCode!;
        var notes = string.IsNullOrWhiteSpace(request.Notes)
            ? $"Retry recorded for prior delivery log {deliveryLogId}."
            : request.Notes!;

        ExternalStatementDeliveryLogResponse deliveryLog;
        if (string.Equals(statement.StatementType, "SUPPLIER_STATEMENT", StringComparison.OrdinalIgnoreCase))
        {
            var supplierLog = _supplierStatementService.RecordDelivery(
                statementId,
                accountingOfficeUserId,
                new RecordSupplierStatementDeliveryRequest(
                    DateTime.UtcNow,
                    channelCode,
                    recipientAddress,
                    deliveryStatusCode,
                    notes));

            deliveryLog = new ExternalStatementDeliveryLogResponse(
                "SUPPLIER_STATEMENT",
                statementId,
                supplierLog.SupplierStatementDeliveryLogId,
                supplierLog.DeliveredAtUtc,
                supplierLog.ChannelCode,
                supplierLog.RecipientAddress,
                supplierLog.DeliveryStatusCode,
                supplierLog.AcknowledgmentStatusCode,
                supplierLog.AcknowledgedAtUtc,
                supplierLog.AcknowledgedByUserId,
                supplierLog.Notes);
        }
        else if (string.Equals(statement.StatementType, "CUSTOMER_STATEMENT", StringComparison.OrdinalIgnoreCase))
        {
            var customerLog = _customerStatementService.RecordDelivery(
                statementId,
                accountingOfficeUserId,
                new RecordCustomerStatementDeliveryRequest(
                    DateTime.UtcNow,
                    channelCode,
                    recipientAddress,
                    deliveryStatusCode,
                    notes));

            deliveryLog = new ExternalStatementDeliveryLogResponse(
                "CUSTOMER_STATEMENT",
                statementId,
                customerLog.CustomerStatementDeliveryLogId,
                customerLog.DeliveredAtUtc,
                customerLog.ChannelCode,
                customerLog.RecipientAddress,
                customerLog.DeliveryStatusCode,
                null,
                null,
                null,
                customerLog.Notes);
        }
        else
        {
            throw new InvalidOperationException($"Statement type '{statement.StatementType}' is not supported for delegated delivery retry.");
        }

        _auditRepository.RecordAction(
            accountingOfficeUserId,
            partyId,
            RetryStatementDeliveryActionCode,
            $"Retried {deliveryLog.StatementType} delivery for statement {statement.StatementNumber} ({statement.StatementId}) from prior log {deliveryLogId} via {deliveryLog.ChannelCode} with status {deliveryLog.DeliveryStatusCode}.");
        return deliveryLog;
    }

    public ExternalStatementDocumentResponse GenerateCurrentUserClientStatement(long accountingOfficeUserId, long partyId, GenerateAccountingOfficeClientStatementRequest request)
    {
        EnsureAssigned(accountingOfficeUserId, partyId);
        var party = _partyOnboardingService.GetParties()
            .SingleOrDefault(entry => entry.PartyId == partyId)
            ?? throw new InvalidOperationException($"Assigned client party '{partyId}' was not found.");

        if (string.Equals(party.PartyType, "SUPPLIER", StringComparison.OrdinalIgnoreCase))
        {
            _supplierStatementService.GenerateStatement(
                accountingOfficeUserId,
                new CreateSupplierStatementRequest(
                    partyId,
                    request.DateFrom,
                    request.DateTo,
                    request.CurrencyCode));
        }
        else if (string.Equals(party.PartyType, "CUSTOMER", StringComparison.OrdinalIgnoreCase))
        {
            _customerStatementService.GenerateStatement(
                accountingOfficeUserId,
                new CreateCustomerStatementRequest(
                    partyId,
                    request.DateFrom,
                    request.DateTo,
                    request.CurrencyCode));
        }
        else
        {
            throw new InvalidOperationException("Only supplier or customer parties support statement generation in the Accounting Office lane.");
        }

        var generated = _externalPortalService.GetStatementDocuments(partyId)
            .OrderByDescending(item => item.GeneratedAtUtc)
            .ThenByDescending(item => item.StatementId)
            .FirstOrDefault()
            ?? throw new InvalidOperationException("Statement generation completed but no statement document was found.");

        _auditRepository.RecordAction(
            accountingOfficeUserId,
            partyId,
            GenerateStatementActionCode,
            $"Generated {generated.StatementType} statement {generated.StatementNumber} ({generated.StatementId}) for assigned client.");
        return generated;
    }

    public string ExportCurrentUserClientReportCsv(long accountingOfficeUserId, long partyId)
    {
        var workspace = BuildClientWorkspace(accountingOfficeUserId, partyId);
        var rows = new[]
        {
            "Metric,Value",
            $"Client Code,{EscapeCsv(workspace.Client.PartyCode)}",
            $"Client Name,{EscapeCsv(workspace.Client.PartyName)}",
            $"Client Type,{EscapeCsv(workspace.Client.PartyType)}",
            $"Orders Count,{workspace.Orders.Count}",
            $"Invoices Count,{workspace.Invoices.Count}",
            $"Payments Count,{workspace.Payments.Count}",
            $"Compliance Documents Count,{workspace.ComplianceDocuments.Count}",
            $"Customer Documents Count,{workspace.CustomerDocuments.Count}",
            $"Service Requests Count,{workspace.ServiceRequests.Count}",
            $"Statement Currency,{EscapeCsv(workspace.StatementSummary.CurrencyCode)}",
            $"Statement Balance,{workspace.StatementSummary.StatementBalanceAmount}",
            $"Open Invoice Amount,{workspace.StatementSummary.OpenInvoiceAmount}",
            $"Overdue Invoice Amount,{workspace.StatementSummary.OverdueInvoiceAmount}",
            $"Unapplied Payment Amount,{workspace.StatementSummary.UnappliedPaymentAmount}"
        };

        _auditRepository.RecordAction(accountingOfficeUserId, partyId, ExportClientReportActionCode, "Exported delegated client report as CSV.");
        return string.Join(Environment.NewLine, rows);
    }

    public IReadOnlyCollection<AccountingOfficeDelegatedActivityResponse> GetCurrentUserActivity(long accountingOfficeUserId, long? partyId = null) =>
        _auditRepository.GetActions(accountingOfficeUserId, partyId).Select(Map).ToArray();

    private AccountingOfficeClientWorkspaceResponse BuildClientWorkspace(long accountingOfficeUserId, long partyId)
    {
        EnsureAssigned(accountingOfficeUserId, partyId);

        var party = _partyOnboardingService.GetParties()
            .SingleOrDefault(entry => entry.PartyId == partyId)
            ?? throw new InvalidOperationException($"Assigned client party '{partyId}' was not found.");

        var supplierProfile = _supplierProfileService.GetSupplierProfiles(activeOnly: false, businessPartyId: partyId).FirstOrDefault();
        var customerProfile = _customerProfileService.GetCustomerProfiles(activeOnly: false, businessPartyId: partyId).FirstOrDefault();

        return new AccountingOfficeClientWorkspaceResponse(
            party,
            supplierProfile,
            customerProfile,
            _externalPortalService.GetOrders(partyId),
            _externalPortalService.GetInvoices(partyId),
            _externalPortalService.GetPayments(partyId),
            _externalPortalService.GetStatementSummary(partyId),
            _partyOnboardingService.GetComplianceDocuments(partyId),
            _externalPortalService.GetCustomerDocuments(partyId),
            string.Equals(party.PartyType, "CUSTOMER", StringComparison.OrdinalIgnoreCase)
                ? _externalPortalService.GetCustomerServiceRequests(partyId)
                : Array.Empty<ExternalCustomerServiceRequestResponse>());
    }

    private void EnsureAssigned(long accountingOfficeUserId, long partyId)
    {
        if (!_assignmentRepository.IsAssigned(accountingOfficeUserId, partyId))
        {
            throw new InvalidOperationException("Accounting Office user is not assigned to the requested client.");
        }
    }

    private ExternalInvoiceResponse ResolveAssignedClientInvoice(long accountingOfficeUserId, long partyId, long invoiceId)
    {
        EnsureAssigned(accountingOfficeUserId, partyId);
        var invoice = _externalPortalService.GetInvoices(partyId)
            .SingleOrDefault(entry => entry.InvoiceId == invoiceId);

        return invoice ?? throw new InvalidOperationException("The requested invoice is not available for the assigned client.");
    }

    private ExternalStatementDocumentResponse ResolveAssignedClientStatement(long accountingOfficeUserId, long partyId, long statementId)
    {
        EnsureAssigned(accountingOfficeUserId, partyId);
        var statement = _externalPortalService.GetStatementDocuments(partyId)
            .SingleOrDefault(entry => entry.StatementId == statementId);

        return statement ?? throw new InvalidOperationException("The requested statement is not available for the assigned client.");
    }

    private static string ResolveEtaReadinessCode(AccountingOfficeClientWorkspaceResponse workspace, int pendingOnboardingCaseCount)
    {
        if (pendingOnboardingCaseCount > 0)
        {
            return "ONBOARDING_PENDING";
        }

        if (workspace.ComplianceDocuments.Count == 0)
        {
            return "DOCUMENT_GAPS";
        }

        if (workspace.Invoices.Count == 0)
        {
            return "NO_INVOICES_READY";
        }

        return "READY_FOR_GOVERNED_SUBMISSION_REVIEW";
    }

    private static string ResolveSubmissionReadinessSummary(AccountingOfficeClientWorkspaceResponse workspace, string etaReadinessCode, int pendingOnboardingCaseCount) =>
        etaReadinessCode switch
        {
            "ONBOARDING_PENDING" => $"Onboarding approval is still pending for {pendingOnboardingCaseCount} case(s) before governed submission work can proceed.",
            "DOCUMENT_GAPS" => "Compliance documents still need to be completed before the office proceeds with governed submission follow-up.",
            "NO_INVOICES_READY" => "The client is approved, but there are no invoices ready yet for ETA-facing delegated submission work.",
            _ => $"The client has {workspace.Invoices.Count} invoice(s) and {workspace.ComplianceDocuments.Count} compliance document(s) ready for governed submission review."
        };

    private static string EscapeCsv(string? value)
    {
        var normalized = value ?? string.Empty;
        var escaped = normalized.Replace("\"", "\"\"");
        return $"\"{escaped}\"";
    }

    private static AccountingOfficeClientAssignmentResponse Map(AccountingOfficeClientAssignmentView view) =>
        new(
            view.AccountingOfficeUserId,
            view.PartyId,
            view.PartyCode,
            view.PartyName,
            view.PartyType,
            view.Email,
            view.MobileNumber,
            view.AssignedAtUtc,
            view.AssignedByUserId);

    private static AccountingOfficeDelegatedActivityResponse Map(AccountingOfficeDelegatedActivityView view) =>
        new(
            view.AuditEventId,
            view.ActionCode,
            view.AccountingOfficeUserId,
            view.AccountingOfficeLoginName,
            view.AccountingOfficeDisplayName,
            view.TargetPartyId,
            view.TargetPartyCode,
            view.TargetPartyName,
            view.DetailsText,
            view.OccurredAtUtc);
}
