import crypto from 'crypto';
import { storage } from '../storage';
import { PRODUCTION_CONFIG, validateProductionConfig, getEnvironmentConfig } from '../config/production';

// Types pour l'API PaiementPRO
export interface PaymentInitRequest {
  orderId: string;
  amount: number;
  customerEmail: string;
  customerFirstName: string;
  customerLastName: string;
  customerPhoneNumber: string;
  description?: string;
  channel?: 'OMCIV2' | 'MOMO' | 'CARD' | 'FLOOZ' | 'PAYPAL';
}

export interface PaymentInitResponse {
  code: number;
  description: string;
  sessionId?: string;
  redirectUrl?: string;
}

export interface PaymentNotification {
  merchantId: string;
  referenceNumber: string;
  amount: number;
  transactiondt: string;
  customerId: string;
  returnContext: string;
  responsecode: number;
  hashcode: string;
}

export class PaymentService {
  private readonly config = getEnvironmentConfig();
  private readonly merchantId = this.config.PAYMENT.MERCHANT_ID;
  private readonly baseUrl = this.config.PAYMENT.API_BASE_URL;
  private readonly secretKey = process.env.PAIEMENTPRO_SECRET_KEY;
  
  constructor() {
    console.log('PaymentService initialized with merchant ID:', this.merchantId);
    
    // Validation de la configuration production
    if (!validateProductionConfig()) {
      throw new Error('Production configuration validation failed');
    }
    
    if (!this.secretKey) {
      console.error('PAIEMENTPRO_SECRET_KEY not configured!');
      throw new Error('PAIEMENTPRO_SECRET_KEY environment variable is required');
    }
    
    console.log('PaiementPRO configured for:', this.config.IS_PRODUCTION ? 'PRODUCTION (real SOAP API)' : 'DEVELOPMENT (simulation)');
    console.log('Supported payment channels:', this.config.PAYMENT.SUPPORTED_CHANNELS.join(', '));
  }

  /**
   * Initialise une transaction de paiement avec PaiementPRO
   */
  async initializePayment(request: PaymentInitRequest): Promise<PaymentInitResponse> {
    try {
      const referenceNumber = `MEDI-${request.orderId}-${Date.now()}`;
      
      // Construire les URLs de callback en mode production
      const domain = process.env.REPLIT_DOMAINS?.split(',')[0];
      const baseUrl = domain ? this.config.CALLBACKS.getBaseUrl(domain) : 'http://localhost:5000';
      
      // Paramètres pour l'API PaiementPRO
      const params = {
        merchantId: this.merchantId,
        countryCurrencyCode: this.config.PAYMENT.CURRENCY_CODE,
        amount: request.amount,
        customerId: request.orderId,
        customerEmail: request.customerEmail,
        customerFirstName: request.customerFirstName,
        customerLastName: request.customerLastName,
        customerPhoneNumber: request.customerPhoneNumber,
        referenceNumber: referenceNumber,
        notificationURL: domain ? this.config.CALLBACKS.getNotificationUrl(domain) : `${baseUrl}/api/payments/notification`,
        returnURL: domain ? this.config.CALLBACKS.getReturnUrl(domain) : `${baseUrl}/payment/return`,
        description: request.description || 'Paiement MediFlash SOS+',
        returnContext: JSON.stringify({ orderId: request.orderId }),
        channel: request.channel || '', // Laisser vide pour choix automatique
        hashcode: this.generateHashCode(referenceNumber, request.amount)
      };

      if (this.config.LOGGING.LOG_PAYMENTS) {
        const logParams = this.config.LOGGING.HIDE_SENSITIVE_DATA 
          ? { ...params, hashcode: '[HIDDEN]', merchantId: '[HIDDEN]' }
          : params;
        console.log('Initializing payment with params:', logParams);
      }

      // Simuler l'appel SOAP (remplacer par vraie implémentation SOAP)
      const response = await this.callSoapAPI('initTransact', params);
      
      if (response.Code === 0) {
        // Enregistrer la transaction en base
        await this.recordPaymentAttempt({
          orderId: request.orderId,
          referenceNumber,
          amount: request.amount,
          sessionId: response.Sessionid,
          status: 'INITIATED'
        });

        return {
          code: 0,
          description: 'Transaction initialisée avec succès',
          sessionId: response.Sessionid,
          redirectUrl: `${this.baseUrl}/webservice/onlinepayment/processing_v2.php?sessionid=${response.Sessionid}`
        };
      }

      return {
        code: response.Code,
        description: this.getErrorDescription(response.Code),
      };

    } catch (error: any) {
      console.error('Payment initialization error:', error);
      return {
        code: -1,
        description: 'Erreur lors de l\'initialisation du paiement'
      };
    }
  }

  /**
   * Traite les notifications de callback de PaiementPRO
   */
  async handlePaymentNotification(notification: PaymentNotification): Promise<boolean> {
    try {
      console.log('Processing payment notification:', notification);

      // Vérifier le hashcode pour la sécurité
      const expectedHash = this.generateHashCode(notification.referenceNumber, notification.amount);
      if (notification.hashcode !== expectedHash) {
        console.error('Invalid hashcode in notification');
        return false;
      }

      // Extraire l'orderId du returnContext
      const context = JSON.parse(notification.returnContext || '{}');
      const orderId = context.orderId;

      if (!orderId) {
        console.error('No orderId in notification context');
        return false;
      }

      // Mettre à jour le statut du paiement
      const success = notification.responsecode === 0;
      await this.updatePaymentStatus(orderId, success ? 'COMPLETED' : 'FAILED', notification);

      if (success) {
        // Créditer le wallet du client
        await this.creditUserWallet(orderId, notification.amount);
        
        // Mettre à jour le statut de la commande (DELIVERED = payée et livrée)
        await storage.updateOrder(orderId, { 
          status: 'DELIVERED'
        });

        console.log(`Payment successful for order ${orderId}, amount: ${notification.amount} FCFA`);
      } else {
        console.log(`Payment failed for order ${orderId}`);
      }

      return true;

    } catch (error: any) {
      console.error('Error processing payment notification:', error);
      return false;
    }
  }

  /**
   * Génère le hashcode de sécurité
   */
  private generateHashCode(referenceNumber: string, amount: number): string {
    const data = `${this.merchantId}${referenceNumber}${amount}${this.secretKey}`;
    return crypto.createHash(this.config.SECURITY.HASH_ALGORITHM).update(data).digest('hex');
  }

  /**
   * Appel SOAP à l'API PaiementPRO en mode production
   */
  private async callSoapAPI(method: string, params: any): Promise<any> {
    try {
      console.log(`SOAP call to ${method} with merchant ${this.merchantId}`);
      
      // En développement, utiliser une simulation
      if (!this.config.USE_REAL_SOAP_API) {
        console.log('Development mode: Using simulated SOAP response');
        if (method === 'initTransact') {
          return {
            Code: 0,
            Description: 'Succès (simulation)',
            Sessionid: `DEV_SESSION_${Date.now()}_${Math.random().toString(36).substring(7)}`
          };
        }
        return { Code: -1, Description: 'Méthode non supportée (simulation)' };
      }

      // En production, utiliser la vraie API SOAP
      const soap = require('soap');
      const client = await soap.createClientAsync(this.config.PAYMENT.WSDL_URL, {
        wsdl_options: {
          timeout: this.config.PAYMENT.TIMEOUT,
          'cache-control': 'no-cache'
        }
      });

      // Masquer les données sensibles dans les logs de production
      const logParams = this.config.LOGGING.HIDE_SENSITIVE_DATA 
        ? { ...params, hashcode: '[HIDDEN]', merchantId: '[HIDDEN]' }
        : params;
      
      if (this.config.LOGGING.LOG_SOAP_REQUESTS) {
        console.log('SOAP request params:', logParams);
      }

      // Appeler la méthode SOAP
      const [result] = await client[method + 'Async'](params);
      
      if (this.config.LOGGING.LOG_PAYMENTS) {
        console.log(`SOAP response:`, result);
      }
      
      return result;

    } catch (error: any) {
      console.error('SOAP API Error:', error);
      return {
        Code: -1,
        Description: `Erreur SOAP: ${error.message}`
      };
    }
  }

  /**
   * Enregistre une tentative de paiement
   */
  private async recordPaymentAttempt(data: {
    orderId: string;
    referenceNumber: string;
    amount: number;
    sessionId: string;
    status: string;
  }): Promise<void> {
    try {
      // Enregistrer dans la base de données
      console.log('Recording payment attempt:', data);
      // TODO: Ajouter table payments dans le schema et storage
    } catch (error) {
      console.error('Error recording payment attempt:', error);
    }
  }

  /**
   * Met à jour le statut d'un paiement
   */
  private async updatePaymentStatus(orderId: string, status: string, notification: PaymentNotification): Promise<void> {
    try {
      console.log(`Updating payment status for order ${orderId} to ${status}`);
      // TODO: Mettre à jour la table payments
    } catch (error) {
      console.error('Error updating payment status:', error);
    }
  }

  /**
   * Crédite le wallet de l'utilisateur
   */
  private async creditUserWallet(orderId: string, amount: number): Promise<void> {
    try {
      // Pour l'instant, utiliser l'API existante des commandes
      const orders = await storage.getAllOrders();
      const order = orders.find(o => o.id === orderId);
      
      if (!order) {
        console.error('Order not found for wallet credit:', orderId);
        return;
      }

      console.log(`Crediting wallet for user ${order.clientId}, amount: ${amount} FCFA`);
      
      // TODO: Implémenter le crédit wallet dans le storage
      // await storage.creditWallet(order.clientId, amount, 'PAYMENT_RECEIVED', orderId);
      
    } catch (error) {
      console.error('Error crediting user wallet:', error);
    }
  }

  /**
   * Récupère la description d'erreur
   */
  private getErrorDescription(code: number): string {
    const errorCodes: { [key: number]: string } = {
      0: 'Succès',
      10: 'Paramètres insuffisants',
      11: 'ID marchand inconnu',
      '-1': 'Erreur d\'initialisation'
    };

    return errorCodes[code] || 'Erreur inconnue';
  }

  /**
   * Obtient les canaux de paiement disponibles
   */
  getAvailableChannels(): Array<{ code: string; name: string; description: string }> {
    return [
      {
        code: 'OMCIV2',
        name: 'Orange Money',
        description: 'Paiement via Orange Money'
      },
      {
        code: 'MOMO', 
        name: 'MTN Mobile Money',
        description: 'Paiement via MTN Mobile Money'
      },
      {
        code: 'FLOOZ',
        name: 'Moov Money',
        description: 'Paiement via Moov Money (Flooz)'
      },
      {
        code: 'CARD',
        name: 'Carte Bancaire',
        description: 'Paiement par carte bancaire'
      }
    ];
  }
}

// Instance singleton
export const paymentService = new PaymentService();