import { DocumentType } from '../../../shared/enums.js';
import { IssuedDocumentsProvider } from '../../documents/providers/issued-documents.provider.js';
import { ClientsProvider } from '../../financial-entities/providers/clients.provider.js';
import { calculateAmountConfidence } from '../helpers/amount-confidence.helper.js';
import { calculateBusinessConfidence } from '../helpers/business-confidence.helper.js';
import { calculateCurrencyConfidence } from '../helpers/currency-confidence.helper.js';
import { calculateDateConfidence } from '../helpers/date-confidence.helper.js';
import { calculateOverallConfidence } from '../helpers/overall-confidence.helper.js';
import { aggregateDocuments } from './document-aggregator.js';
import { aggregateTransactions } from './transaction-aggregator.js';
/**
 * Select appropriate transaction date based on document type
 * Per specification:
 * - INVOICE/CREDIT_INVOICE: Use event_date
 * - RECEIPT/INVOICE_RECEIPT: Use debit_date (debit_timestamp or debit_date)
 * - OTHER/PROFORMA/UNPROCESSED: Calculate both and use better score
 *
 * @param transaction - Aggregated transaction data
 * @param documentType - Document type being matched
 * @returns The date to use for matching
 */
export function selectTransactionDate(transaction, documentType) {
    switch (documentType) {
        case DocumentType.Invoice:
        case DocumentType.CreditInvoice:
        case DocumentType.Receipt:
        case DocumentType.InvoiceReceipt:
            // For invoices, use event_date
            return transaction.date;
        case DocumentType.Other:
        case DocumentType.Proforma:
        case DocumentType.Unprocessed:
            // For flexible types, use event_date as default
            // (caller should calculate both and use better score)
            return transaction.date;
        default:
            // Fallback to event_date for unknown types
            return transaction.date;
    }
}
/**
 * Score a potential match between transaction charge and document charge
 * Aggregates data from both charges and calculates confidence score
 *
 * @param txCharge - Transaction charge to match
 * @param docCharge - Document charge candidate
 * @param userId - Current user UUID for business extraction
 * @param injector - Optional GraphQL modules injector for provider access (for client matching)
 * @returns Match score with confidence and component breakdown
 * @throws Error if aggregation fails (mixed currencies, multiple businesses, etc.)
 */
export async function scoreMatch(txCharge, docCharge, userId, injector) {
    // Aggregate transaction data
    const aggregatedTransaction = aggregateTransactions(txCharge.transactions);
    // Aggregate document data (includes business extraction and amount normalization)
    const aggregatedDocument = aggregateDocuments(docCharge.documents, userId);
    // // For flexible document types, try both dates and use the better score
    // if (
    //   aggregatedDocument.type === 'OTHER' ||
    //   aggregatedDocument.type === 'PROFORMA' ||
    //   aggregatedDocument.type === 'UNPROCESSED'
    // ) {
    //   // Calculate score with event_date
    //   const scoreWithEventDate = await calculateScoreWithDate(
    //     aggregatedTransaction,
    //     aggregatedDocument,
    //     aggregatedTransaction.date,
    //     docCharge.chargeId,
    //     injector,
    //   );
    //   // Calculate score with debit_date (if available)
    //   if (aggregatedTransaction.debitDate) {
    //     const scoreWithDebitDate = await calculateScoreWithDate(
    //       aggregatedTransaction,
    //       aggregatedDocument,
    //       aggregatedTransaction.debitDate,
    //       docCharge.chargeId,
    //       injector,
    //     );
    //     // Return the better score
    //     return scoreWithEventDate.confidenceScore > scoreWithDebitDate.confidenceScore
    //       ? scoreWithEventDate
    //       : scoreWithDebitDate;
    //   }
    //   return scoreWithEventDate;
    // }
    // For specific document types, use the appropriate date
    const transactionDate = selectTransactionDate(aggregatedTransaction, aggregatedDocument.type);
    return calculateScoreWithDate(aggregatedTransaction, aggregatedDocument, transactionDate, docCharge.chargeId, injector);
}
/**
 * Helper function to calculate match score with a specific transaction date
 * @param transaction - Aggregated transaction
 * @param document - Aggregated document
 * @param transactionDate - Date to use from transaction
 * @param chargeId - Document charge ID
 * @param injector - Optional GraphQL modules injector for provider access
 * @returns Match score
 */
async function calculateScoreWithDate(transaction, document, transactionDate, chargeId, injector) {
    // Check if transaction and document share the same business entity
    const businessesMatch = transaction.businessId != null && transaction.businessId === document.businessId;
    // If businesses match, verify if it's a registered CLIENT
    let isClientMatch = false;
    if (businessesMatch && transaction.businessId) {
        try {
            const client = await injector
                .get(ClientsProvider)
                .getClientByIdLoader.load(transaction.businessId);
            // isClientMatch is true only if business is a registered client
            isClientMatch = client != null;
        }
        catch (error) {
            console.error(`Error looking up client for business ID ${transaction.businessId}:`, error);
            isClientMatch = false;
        }
    }
    // Determine gentle eligibility for client matches
    // Conditions:
    // - Same business and registered client
    // - Document type is INVOICE or PROFORMA
    // - Document status is OPEN (via issued documents status by charge id)
    // - Document date <= transaction date (date-only compare)
    let isGentleEligible = false;
    if (isClientMatch) {
        // Type gating
        const typeIsEligible = document.type === DocumentType.Invoice || document.type === DocumentType.Proforma;
        // Date-only comparison: doc.date <= transactionDate
        const docDate = new Date(document.date.getFullYear(), document.date.getMonth(), document.date.getDate());
        const txDate = new Date(transactionDate.getFullYear(), transactionDate.getMonth(), transactionDate.getDate());
        const dateIsEligible = docDate.getTime() <= txDate.getTime();
        // Status gating via DataLoader
        let statusIsEligible;
        try {
            const status = (await injector
                .get(IssuedDocumentsProvider)
                .getIssuedDocumentsStatusByChargeIdLoader.load(chargeId));
            // Expect shape with open_docs_flag boolean
            statusIsEligible = !!(status && status.open_docs_flag === true);
        }
        catch {
            // If status lookup fails, treat as ineligible (do not throw)
            statusIsEligible = false;
        }
        isGentleEligible = typeIsEligible && dateIsEligible && statusIsEligible;
    }
    // Calculate individual confidence scores
    const amountScore = calculateAmountConfidence(transaction.amount, document.amount);
    const currencyScore = calculateCurrencyConfidence(transaction.currency, document.currency);
    const businessScore = calculateBusinessConfidence(transaction.businessId, document.businessId);
    // Use gentle eligibility to compute date confidence
    const dateScore = calculateDateConfidence(transactionDate, document.date, isGentleEligible);
    // Create components object
    const components = {
        amount: amountScore,
        currency: currencyScore,
        business: businessScore,
        date: dateScore,
    };
    // Calculate overall confidence
    const confidenceScore = calculateOverallConfidence(components);
    return {
        chargeId,
        confidenceScore,
        components,
        // Expose gentle flag for tie-breaker handling upstream
        // (optional property tolerated by consumer types)
        gentleMode: isGentleEligible,
    };
}
//# sourceMappingURL=match-scorer.provider.js.map