// AS4 Message Validator Service
// Validates messages against JSON schemas

import Ajv, { ValidateFunction } from 'ajv';
import addFormats from 'ajv-formats';
import { MESSAGE_SCHEMAS } from './message-schemas';
import { logger } from '@/infrastructure/monitoring/logger';

const ajv = new Ajv({ allErrors: true, strict: false });
addFormats(ajv);

// Compile schemas
const compiledSchemas: Record<string, ValidateFunction> = {};
for (const [messageType, schema] of Object.entries(MESSAGE_SCHEMAS)) {
  compiledSchemas[messageType] = ajv.compile(schema);
}

export class MessageValidatorService {
  /**
   * Validate message against schema
   */
  validateMessage(message: any): { valid: boolean; errors?: string[] } {
    const businessType = message.BusinessType || message.businessType;

    if (!businessType) {
      return {
        valid: false,
        errors: ['BusinessType is required'],
      };
    }

    const validator = compiledSchemas[businessType];
    if (!validator) {
      return {
        valid: false,
        errors: [`Unknown message type: ${businessType}`],
      };
    }

    const valid = validator(message);
    if (!valid) {
      const errors = validator.errors?.map((err) => {
        return `${err.instancePath || ''} ${err.message || ''}`.trim();
      }) || ['Validation failed'];

      logger.warn('Message validation failed', {
        businessType,
        errors,
      });

      return {
        valid: false,
        errors,
      };
    }

    return { valid: true };
  }

  /**
   * Validate instruction message (DBIS.SI.202)
   */
  validateInstruction(message: any): { valid: boolean; errors?: string[] } {
    if (!message.Instr) {
      return {
        valid: false,
        errors: ['Instr object is required'],
      };
    }

    // Additional business validation
    const errors: string[] = [];

    // Validate value date
    const valueDate = new Date(message.Instr.ValueDate);
    const today = new Date();
    today.setHours(0, 0, 0, 0);
    if (valueDate < today) {
      errors.push('ValueDate cannot be in the past');
    }

    // Validate amount
    const amount = parseFloat(message.Instr.Amount);
    if (isNaN(amount) || amount <= 0) {
      errors.push('Amount must be a positive number');
    }

    // Validate accounts
    if (message.Instr.DebtorAccount === message.Instr.CreditorAccount) {
      errors.push('DebtorAccount and CreditorAccount must be different');
    }

    if (errors.length > 0) {
      return {
        valid: false,
        errors,
      };
    }

    return this.validateMessage(message);
  }
}

export const messageValidatorService = new MessageValidatorService();
