/**
 * EvolutionWebhookController.js
 * 
 * Controller for handling Evolution API webhooks
 * Processes incoming events from Evolution API
 * 
 * @module controllers/EvolutionWebhookController
 */

const { logger } = require('../config/logger');
const EvolutionInstance = require('../models/EvolutionInstance');
const eventBus = require('../core/whatsapp/EventBus');
const Events = require('../core/whatsapp/CoreEvents');

/**
 * Evolution Webhook Controller
 * Handles incoming webhooks from Evolution API
 */
class EvolutionWebhookController {
  /**
   * Handle webhook from Evolution API
   * POST /api/webhooks/evolution/:tenantId
   */
  static async handleWebhook(req, res) {
    try {
      console.log('\n\n🔔🔔🔔 WEBHOOK RECEIVED 🔔🔔🔔');
      console.log('═══════════════════════════════════════════════════════════');
      console.log('⏰ Timestamp:', new Date().toISOString());
      console.log('📍 Tenant ID:', req.params.tenantId);
      console.log('📨 Event:', req.body.event);
      console.log('📱 Instance:', req.body.instance);
      console.log('\n📋 Headers:');
      console.log(JSON.stringify(req.headers, null, 2));
      console.log('\n📦 Body completo:');
      console.log(JSON.stringify(req.body, null, 2));
      console.log('═══════════════════════════════════════════════════════════\n');
      
      const tenantId = parseInt(req.params.tenantId);
      const event = req.body.event;
      const data = req.body.data || req.body;

      logger.info('🔔 Evolution webhook received', { 
        tenantId, 
        event,
        instance: data.instance,
        bodyKeys: Object.keys(req.body),
        dataKeys: Object.keys(data),
        fullBody: JSON.stringify(req.body).substring(0, 500)
      });

      // Acknowledge webhook immediately
      res.status(200).json({ success: true });

      // Process webhook asynchronously - pass instance name from root level
      await this.processWebhook(tenantId, event, data, req.body.instance);

    } catch (error) {
      logger.error('Error handling Evolution webhook', { 
        error: error.message,
        stack: error.stack,
        body: req.body
      });
      
      // Still return 200 to prevent Evolution API from retrying
      res.status(200).json({ success: false, error: error.message });
    }
  }

  /**
   * Process webhook event
   * @param {number} tenantId - Tenant ID
   * @param {string} event - Event type
   * @param {Object} data - Event data
   * @param {string} instanceNameFromRoot - Instance name from root level
   */
  static async processWebhook(tenantId, event, data, instanceNameFromRoot) {
    try {
      console.log('\n🔄 PROCESSANDO WEBHOOK:');
      console.log('   Tenant ID:', tenantId);
      console.log('   Event:', event);
      console.log('   Instance (root):', instanceNameFromRoot);
      console.log('   Instance (data):', data.instance);
      
      // Instance name can be at root level or inside data
      const instanceName = instanceNameFromRoot || data.instance;

      if (!instanceName) {
        console.log('❌ ERRO: Webhook sem nome de instância');
        console.log('   Data keys:', Object.keys(data));
        logger.warn('Webhook received without instance name', { tenantId, event, dataKeys: Object.keys(data) });
        return;
      }

      console.log('   ✅ Instance name:', instanceName);
      console.log('   🔍 Buscando instância no banco...');

      // Get instance from database
      const instance = await EvolutionInstance.getByEvolutionId(instanceName);

      if (!instance) {
        console.log('   ❌ ERRO: Instância não encontrada no banco');
        logger.warn('Instance not found for webhook', { tenantId, instanceName, event });
        return;
      }

      console.log('   ✅ Instância encontrada:', instance.id, '-', instance.instance_name);
      console.log('   📌 Tipo de evento:', event);

      // Handle different event types
      switch (event) {
        case 'QRCODE_UPDATED':
        case 'qrcode.updated':
          console.log('   📱 Processando QR Code...');
          await this.handleQRCodeUpdate(instance, data);
          break;

        case 'CONNECTION_UPDATE':
        case 'connection.update':
          console.log('   🔌 Processando atualização de conexão...');
          await this.handleConnectionUpdate(instance, data);
          break;

        case 'MESSAGES_UPSERT':
        case 'messages.upsert':
          console.log('   💬 Processando mensagem recebida...');
          await this.handleMessageReceived(instance, data);
          break;

        case 'MESSAGES_UPDATE':
        case 'messages.update':
          console.log('   ✏️ Processando atualização de mensagem...');
          await this.handleMessageUpdate(instance, data);
          break;

        case 'SEND_MESSAGE':
        case 'send.message':
          console.log('   📤 Processando mensagem enviada...');
          await this.handleMessageSent(instance, data);
          break;

        default:
          console.log('   ⚠️ Evento não tratado:', event);
          logger.info('Unhandled webhook event', { event, instanceName });
      }
      
      console.log('   ✅ Webhook processado com sucesso!\n');

    } catch (error) {
      console.error('   ❌ ERRO ao processar webhook:', error.message);
      logger.error('Error processing webhook', { 
        tenantId,
        event,
        error: error.message,
        stack: error.stack
      });
    }
  }

  /**
   * Handle QR code update
   * @param {Object} instance - Instance data
   * @param {Object} data - Event data
   */
  static async handleQRCodeUpdate(instance, data) {
    try {
      const qrCode = data.qrcode || data.qr || data.base64 || data.code;

      logger.info('QR code update received', { 
        instanceId: instance.id, 
        hasQrCode: !!qrCode,
        dataKeys: Object.keys(data)
      });

      if (!qrCode) {
        logger.warn('QR code update without QR data', { instanceId: instance.id, data });
        return;
      }

      logger.info('Updating QR code in database', { instanceId: instance.id });

      // Update instance with new QR code
      await EvolutionInstance.update(instance.id, {
        qr_code: qrCode,
        status: 'qr_code'
      });

      // Emit Socket.IO event to tenant
      const io = global.io;
      if (io) {
        const tenantNamespace = io.of(`/tenant/${instance.tenant_id}`);
        logger.info('Emitting QR code to socket', { 
          tenantId: instance.tenant_id,
          instanceId: instance.id 
        });
        
        // Emit both event names for compatibility
        tenantNamespace.emit('whatsapp-qr-updated', {
          instanceId: instance.id,
          instanceName: instance.instance_name,
          qrCode: qrCode
        });
        
        tenantNamespace.emit('qr-code', {
          instanceId: instance.id,
          instanceName: instance.instance_name,
          qrCode: qrCode
        });
      } else {
        logger.warn('Socket.IO not available');
      }

    } catch (error) {
      logger.error('Error handling QR code update', { 
        instanceId: instance.id,
        error: error.message
      });
    }
  }

  /**
   * Handle connection status update
   * @param {Object} instance - Instance data
   * @param {Object} data - Event data
   */
  static async handleConnectionUpdate(instance, data) {
    try {
      const state = data.state || data.status;
      const phoneNumber = data.phoneNumber || data.phone;

      logger.info('Connection status updated', { 
        instanceId: instance.id,
        state,
        phoneNumber
      });

      // Map Evolution API states to our status
      const statusMap = {
        'open': 'connected',
        'connecting': 'connecting',
        'close': 'disconnected',
        'qr': 'qr_code'
      };

      const newStatus = statusMap[state] || 'disconnected';

      // Update instance
      const updateData = { status: newStatus };
      
      if (phoneNumber) {
        updateData.phone_number = phoneNumber;
      }

      if (newStatus === 'connected') {
        updateData.last_connected_at = new Date().toISOString().slice(0, 19).replace('T', ' ');
        updateData.error_message = null;
        updateData.qr_code = null;

        // Fetch profile picture from Evolution API
        try {
          logger.info('Fetching profile picture for connected instance', { 
            instanceId: instance.id,
            evolutionInstanceId: instance.evolution_instance_id 
          });

          const instanceInfo = await EvolutionAPIService.getInstanceInfo(instance.evolution_instance_id);
          
          if (instanceInfo) {
            if (instanceInfo.profilePicUrl) {
              updateData.profile_picture_url = instanceInfo.profilePicUrl;
              logger.info('Profile picture URL saved', { 
                instanceId: instance.id,
                profilePicUrl: instanceInfo.profilePicUrl 
              });
            }
            
            if (instanceInfo.profileName) {
              updateData.profile_name = instanceInfo.profileName;
              logger.info('Profile name saved', { 
                instanceId: instance.id,
                profileName: instanceInfo.profileName 
              });
            }
          }
        } catch (profileError) {
          logger.error('Error fetching profile picture', {
            instanceId: instance.id,
            error: profileError.message
          });
          // Don't fail the connection update if profile fetch fails
        }
      }

      await EvolutionInstance.update(instance.id, updateData);

      // Emit Socket.IO event to tenant
      const io = global.io;
      if (io) {
        const tenantNamespace = io.of(`/tenant/${instance.tenant_id}`);
        
        const eventData = {
          instanceId: instance.id,
          instanceName: instance.instance_name,
          status: newStatus,
          phoneNumber: phoneNumber,
          profilePictureUrl: updateData.profile_picture_url,
          profileName: updateData.profile_name
        };
        
        // Emit multiple event names for compatibility
        tenantNamespace.emit('whatsapp-status-changed', eventData);
        tenantNamespace.emit('connection-update', eventData);
        
        logger.info('Emitted connection status to socket', { 
          tenantId: instance.tenant_id,
          instanceId: instance.id,
          status: newStatus
        });
      }

    } catch (error) {
      logger.error('Error handling connection update', { 
        instanceId: instance.id,
        error: error.message
      });
    }
  }

  /**
   * Handle incoming message
   * @param {Object} instance - Instance data
   * @param {Object} data - Event data
   */
  static async handleMessageReceived(instance, data) {
    try {
      console.log('\n      📨 PROCESSANDO MENSAGEM RECEBIDA:');
      console.log('      Instance ID:', instance.id);
      console.log('      Tenant ID:', instance.tenant_id);
      console.log('      Data keys:', Object.keys(data));
      console.log('      Has messages:', !!data.messages);
      console.log('      Message count:', data.messages?.length || 0);
      
      logger.info('Message received via Evolution webhook', { 
        instanceId: instance.id,
        tenantId: instance.tenant_id,
        dataKeys: Object.keys(data),
        hasMessages: !!data.messages,
        messageCount: data.messages?.length || 0,
        fullData: JSON.stringify(data).substring(0, 1000)
      });

      // Transform Evolution API message format to our format
      const messages = data.messages || [data];
      
      console.log('      📋 Total de mensagens a processar:', messages.length);

      for (const message of messages) {
        console.log('\n      ➡️ Processando mensagem:');
        console.log('         Message keys:', Object.keys(message));
        console.log('         Message type:', message.messageType);
        console.log('         Has key:', !!message.key);
        console.log('         Remote JID:', message.key?.remoteJid);
        console.log('         From me:', message.key?.fromMe);
        
        // Ignorar mensagens enviadas por nós
        if (message.key?.fromMe) {
          console.log('         ⏭️ Ignorando mensagem enviada por nós');
          continue;
        }
        
        logger.info('Emitting message to event bus', {
          instanceId: instance.id,
          messageKeys: Object.keys(message),
          messageType: message.messageType,
          hasKey: !!message.key,
          keyRemoteJid: message.key?.remoteJid
        });

        console.log('         🚀 Emitindo para o event bus...');

        // Emit to event bus for processing
        eventBus.emit(Events.MESSAGE_RECEIVED, {
          channel: 'evolution',
          tenantId: instance.tenant_id,
          instanceId: instance.id,
          sessionId: instance.evolution_instance_id,
          upsert: {
            messages: [message],
            type: 'notify'
          },
          message: message
        });
        
        console.log('         ✅ Mensagem emitida para o event bus');
      }
      
      console.log('      ✅ Todas as mensagens processadas\n');

    } catch (error) {
      console.error('      ❌ ERRO ao processar mensagem:', error.message);
      console.error('      Stack:', error.stack);
      logger.error('Error handling message received', { 
        instanceId: instance.id,
        error: error.message,
        stack: error.stack
      });
    }
  }

  /**
   * Handle message update (read, delivered, etc.)
   * @param {Object} instance - Instance data
   * @param {Object} data - Event data
   */
  static async handleMessageUpdate(instance, data) {
    try {
      logger.info('Message update received', { 
        instanceId: instance.id,
        update: data
      });

      // Emit Socket.IO event to tenant
      const io = global.io;
      if (io) {
        const tenantNamespace = io.of(`/tenant/${instance.tenant_id}`);
        tenantNamespace.emit('whatsapp-message-update', {
          instanceId: instance.id,
          update: data
        });
      }

    } catch (error) {
      logger.error('Error handling message update', { 
        instanceId: instance.id,
        error: error.message
      });
    }
  }

  /**
   * Handle message sent confirmation
   * @param {Object} instance - Instance data
   * @param {Object} data - Event data
   */
  static async handleMessageSent(instance, data) {
    try {
      logger.info('Message sent confirmation', { 
        instanceId: instance.id,
        messageId: data.key?.id
      });

      // Emit Socket.IO event to tenant
      const io = global.io;
      if (io) {
        const tenantNamespace = io.of(`/tenant/${instance.tenant_id}`);
        tenantNamespace.emit('whatsapp-message-sent', {
          instanceId: instance.id,
          messageId: data.key?.id,
          status: 'sent'
        });
      }

    } catch (error) {
      logger.error('Error handling message sent', { 
        instanceId: instance.id,
        error: error.message
      });
    }
  }
}

module.exports = EvolutionWebhookController;
