// Worldwide AML Pattern Language (WAPL) - Main Service

import prisma from '@/shared/database/prisma';
import { v4 as uuidv4 } from 'uuid';
import { WAPLPattern, PatternMatch, PatternAlert } from './types';
import { patternLibraryService } from './pattern-library.service';
import { patternCompilerService } from './pattern-compiler.service';
import { mlEnhancementService } from './ml-enhancement.service';
import { logger } from '@/infrastructure/monitoring/logger';


export class WAPLService {
  /**
   * Initialize WAPL with default patterns
   */
  async initialize(): Promise<void> {
    logger.info('Initializing WAPL with default patterns');
    await patternLibraryService.initializeDefaultPatterns();
    logger.info('WAPL initialization completed');
  }

  /**
   * Match transaction against all active patterns
   */
  async matchPatterns(transactionId: string): Promise<PatternMatch[]> {
    const patterns = await patternLibraryService.getActivePatterns();
    const matches: PatternMatch[] = [];

    for (const pattern of patterns) {
      const match = await this.matchPattern(transactionId, pattern);
      if (match) {
        matches.push(match);
      }
    }

    // Apply ML enhancements
    const enhancedMatches = await mlEnhancementService.enhancePatternMatching(
      transactionId,
      matches
    );

    // Store matches
    for (const match of enhancedMatches) {
      await prisma.pattern_matches.create({
        data: {
          id: match.id,
          patternId: match.patternId,
          transactionId: match.transactionId,
          matchScore: match.matchScore,
          matchedConditions: match.matchedConditions,
          alertGenerated: match.alertGenerated,
        },
      });

      // Generate alert if threshold met
      if (match.matchScore >= 0.7 && !match.alertGenerated) {
        await this.generateAlert(match);
      }
    }

    return enhancedMatches;
  }

  /**
   * Match transaction against a specific pattern
   */
  private async matchPattern(
    transactionId: string,
    pattern: WAPLPattern
  ): Promise<PatternMatch | null> {
    // Compile pattern
    const conditions = patternCompilerService.compilePattern(pattern);

    // Get transaction
    const transaction = await prisma.ledger_entries.findUnique({
      where: { id: transactionId },
      include: {
        bank_accounts_ledger_entries_debitAccountIdTobank_accounts: true,
        bank_accounts_ledger_entries_creditAccountIdTobank_accounts: true,
      },
    });

    if (!transaction) {
      return null;
    }

    // Evaluate conditions
    const matchedConditions: string[] = [];
    let matchScore = 0;

    for (const condition of conditions) {
      const matches = await this.evaluateCondition(transaction, condition);
      if (matches) {
        matchedConditions.push(condition.type);
        matchScore += 0.3; // Each condition contributes to score
      }
    }

    if (matchedConditions.length === 0) {
      return null;
    }

    // Normalize score
    matchScore = Math.min(1.0, matchScore);

    return {
      id: `WAPL-MATCH-${uuidv4()}`,
      patternId: pattern.id,
      transactionId,
      matchScore,
      matchedConditions,
      alertGenerated: false,
      detectedAt: new Date(),
    };
  }

  /**
   * Evaluate a pattern condition
   */
  private async evaluateCondition(transaction: any, condition: any): Promise<boolean> {
    switch (condition.type) {
      case 'VELOCITY':
        // Check transaction velocity
        const recentTransactions = await prisma.ledger_entries.findMany({
          where: {
            OR: [
              { debitAccountId: transaction.debitAccountId },
              { creditAccountId: transaction.creditAccountId },
            ],
            createdAt: {
              gte: new Date(Date.now() - 24 * 60 * 60 * 1000),
            },
          },
        });
        return recentTransactions.length > (condition.value || 10);

      case 'HOP_COUNT':
        // Simplified hop count check
        return true; // Placeholder

      case 'FX_TRADE':
        // Check if FX trade
        return transaction.assetType === 'fx';

      default:
        return false;
    }
  }

  /**
   * Generate alert for pattern match
   */
  private async generateAlert(match: PatternMatch): Promise<void> {
    const pattern = await patternLibraryService.getPattern(match.patternId);

    if (!pattern) {
      return;
    }

    const alert = await prisma.pattern_alerts.create({
      data: {
        id: `WAPL-ALERT-${uuidv4()}`,
        patternMatchId: match.id,
        transactionId: match.transactionId,
        patternCode: pattern.patternCode,
        severity: pattern.severity,
        description: `Pattern ${pattern.name} detected with score ${match.matchScore.toFixed(2)}`,
        status: 'PENDING',
        createdAt: new Date(),
        updatedAt: new Date(),
      },
    });

    // Update match
    await prisma.pattern_matches.update({
      where: { id: match.id },
      data: { alertGenerated: true },
    });

    logger.warn(`Generated WAPL alert: ${alert.id}`, {
      patternCode: pattern.patternCode,
      severity: pattern.severity,
    });
  }

  /**
   * Get alerts
   */
  async getAlerts(status?: string) {
    const where: any = {};
    if (status) {
      where.status = status;
    }

    return prisma.pattern_alerts.findMany({
      where,
      orderBy: { createdAt: 'desc' },
      take: 100,
    });
  }
}

export const waplService = new WAPLService();

