/**
 * Evolution API Service
 * Handles communication with Evolution API
 * 
 * @module services/EvolutionAPIService
 */

const axios = require('axios');
const { logger } = require('../config/logger');

class EvolutionAPIService {
  constructor() {
    // Don't cache these values - always read from process.env
    logger.info('Evolution API Service initialized');
  }

  /**
   * Get axios client with current environment variables
   * @returns {Object} Axios instance
   */
  getClient() {
    const baseURL = process.env.EVOLUTION_API_URL || 'http://localhost:8080';
    const apiKey = process.env.EVOLUTION_API_KEY;

    return axios.create({
      baseURL: baseURL,
      headers: {
        'Content-Type': 'application/json',
        'apikey': apiKey
      },
      timeout: 30000
    });
  }

  /**
   * Create new instance
   * @param {string} instanceName - Unique instance name
   * @param {string} webhookUrl - Webhook URL for events
   * @param {Array} webhookEvents - Events to subscribe
   * @returns {Promise<Object>} Instance data
   */
  async createInstance(instanceName, webhookUrl, webhookEvents = []) {
    try {
      logger.info('Creating Evolution API instance', { instanceName, webhookUrl, webhookEvents });

      const client = this.getClient();
      
      // Log the request details
      logger.info('Evolution API request details', {
        baseURL: process.env.EVOLUTION_API_URL,
        hasApiKey: !!process.env.EVOLUTION_API_KEY,
        instanceName,
        webhookUrl
      });
      
      const response = await client.post('/instance/create', {
        instanceName,
        qrcode: true,
        integration: 'WHATSAPP-BAILEYS'
      });

      logger.info('Instance created successfully', { instanceName, data: response.data });

      // CRITICAL: Set webhook immediately after creation with webhookByEvents: true
      if (webhookUrl) {
        try {
          logger.info('Configuring webhook with webhookByEvents: true', { 
            instanceName, 
            webhookUrl,
            events: webhookEvents 
          });
          
          await this.setWebhook(instanceName, webhookUrl, webhookEvents);
          
          logger.info('✅ Webhook configured successfully with webhookByEvents: true', { instanceName });
        } catch (webhookError) {
          logger.error('❌ Failed to set webhook during instance creation', {
            instanceName,
            webhookUrl,
            error: webhookError.message,
            stack: webhookError.stack,
            response: webhookError.response?.data
          });
          // Don't throw - instance is still usable, but log prominently
          logger.warn('⚠️  Instance created but webhook configuration failed - manual configuration may be needed');
        }
      }

      return response.data;
    } catch (error) {
      logger.error('Error creating Evolution API instance', {
        instanceName,
        error: error.message,
        response: error.response?.data,
        status: error.response?.status,
        stack: error.stack
      });
      throw new Error(`Failed to create instance: ${error.response?.data?.message || error.message}`);
    }
  }

  /**
   * Set webhook for instance
   * @param {string} instanceName - Instance name
   * @param {string} webhookUrl - Webhook URL
   * @param {Array} events - Events to subscribe
   * @returns {Promise<Object>} Webhook data
   */
  async setWebhook(instanceName, webhookUrl, events = []) {
    try {
      logger.info('Setting webhook for instance', { instanceName, webhookUrl, events });

      const defaultEvents = [
        'QRCODE_UPDATED',
        'CONNECTION_UPDATE',
        'MESSAGES_UPSERT',
        'MESSAGES_UPDATE',
        'SEND_MESSAGE'
      ];

      const client = this.getClient();
      const response = await client.post(`/webhook/set/${instanceName}`, {
        webhook: {
          enabled: true,
          url: webhookUrl,
          webhookByEvents: true,  // CRÍTICO: deve ser true
          webhookBase64: false,
          events: events.length > 0 ? events : defaultEvents,
          headers: {
            'ngrok-skip-browser-warning': 'true'
          }
        }
      });

      logger.info('Webhook set successfully', { instanceName, response: response.data });

      return response.data;
    } catch (error) {
      logger.error('Error setting webhook', {
        instanceName,
        error: error.message,
        response: error.response?.data
      });
      throw new Error(`Failed to set webhook: ${error.response?.data?.message || error.message}`);
    }
  }

  /**
   * Get instance connection status
   * @param {string} instanceName - Instance name
   * @returns {Promise<Object>} Status data
   */
  async getInstanceStatus(instanceName) {
    try {
      logger.info('Getting instance status from Evolution API', { 
        instanceName,
        url: `/instance/connectionState/${instanceName}`,
        baseURL: process.env.EVOLUTION_API_URL
      });
      
      const client = this.getClient();
      const response = await client.get(`/instance/connectionState/${instanceName}`);
      
      logger.info('Instance status retrieved successfully', { 
        instanceName, 
        status: response.data,
        statusCode: response.status
      });

      return response.data;
    } catch (error) {
      logger.error('Error getting instance status from Evolution API', {
        instanceName,
        error: error.message,
        status: error.response?.status,
        statusText: error.response?.statusText,
        responseData: error.response?.data,
        url: error.config?.url,
        baseURL: error.config?.baseURL
      });
      throw new Error(`Failed to get status: ${error.response?.data?.message || error.message}`);
    }
  }

  /**
   * Connect instance (generate QR code)
   * @param {string} instanceName - Instance name
   * @returns {Promise<Object>} Connection data with QR code
   */
  async connectInstance(instanceName) {
    try {
      logger.info('Connecting instance via Evolution API', { 
        instanceName,
        url: `/instance/connect/${instanceName}`,
        baseURL: process.env.EVOLUTION_API_URL
      });

      const client = this.getClient();
      const response = await client.get(`/instance/connect/${instanceName}`);

      logger.info('Instance connection response', { 
        instanceName,
        hasData: !!response.data,
        dataKeys: response.data ? Object.keys(response.data) : [],
        status: response.status,
        fullData: response.data
      });

      return response.data;
    } catch (error) {
      logger.error('Error connecting instance via Evolution API', {
        instanceName,
        error: error.message,
        status: error.response?.status,
        statusText: error.response?.statusText,
        responseData: error.response?.data,
        url: error.config?.url,
        baseURL: error.config?.baseURL
      });
      throw new Error(`Failed to connect: ${error.response?.data?.message || error.message}`);
    }
  }

  /**
   * Disconnect instance
   * @param {string} instanceName - Instance name
   * @returns {Promise<Object>} Disconnect result
   */
  async disconnectInstance(instanceName) {
    try {
      logger.info('Disconnecting instance', { instanceName });

      const client = this.getClient();
      const response = await client.delete(`/instance/logout/${instanceName}`);

      logger.info('Instance disconnected', { instanceName });

      return response.data;
    } catch (error) {
      logger.error('Error disconnecting instance', {
        instanceName,
        error: error.message,
        response: error.response?.data
      });
      throw new Error(`Failed to disconnect: ${error.response?.data?.message || error.message}`);
    }
  }

  /**
   * Delete instance
   * @param {string} instanceName - Instance name
   * @returns {Promise<Object>} Delete result
   */
  async deleteInstance(instanceName) {
    try {
      logger.info('Deleting instance from Evolution API', { 
        instanceName,
        url: `/instance/delete/${instanceName}`,
        baseURL: process.env.EVOLUTION_API_URL
      });

      const client = this.getClient();
      const response = await client.delete(`/instance/delete/${instanceName}`);

      logger.info('Instance deleted from Evolution API successfully', { 
        instanceName,
        status: response.status,
        data: response.data
      });

      return response.data;
    } catch (error) {
      logger.error('Error deleting instance from Evolution API', {
        instanceName,
        error: error.message,
        status: error.response?.status,
        statusText: error.response?.statusText,
        responseData: error.response?.data,
        url: error.config?.url,
        baseURL: error.config?.baseURL
      });
      throw new Error(`Failed to delete: ${error.response?.data?.message || error.message}`);
    }
  }

  /**
   * Send text message
   * @param {string} instanceName - Instance name
   * @param {string} phoneNumber - Recipient phone number (can be remoteJid or just number)
   * @param {string} message - Message text
   * @returns {Promise<Object>} Send result
   */
  async sendTextMessage(instanceName, phoneNumber, message) {
    return this.sendMessage(instanceName, phoneNumber, message);
  }

  /**
   * Send message
   * @param {string} instanceName - Instance name
   * @param {string} phoneNumber - Recipient phone number
   * @param {string} message - Message text
   * @returns {Promise<Object>} Send result
   */
  async sendMessage(instanceName, phoneNumber, message) {
    try {
      logger.info('Sending message via Evolution API', { instanceName, phoneNumber });

      // Format phone number (remove + and @s.whatsapp.net if present)
      const formattedPhone = phoneNumber.replace(/^\+/, '').replace('@s.whatsapp.net', '').replace('@lid', '');

      const client = this.getClient();
      const response = await client.post(`/message/sendText/${instanceName}`, {
        number: formattedPhone,
        text: message
      });

      logger.info('Message sent successfully', { instanceName, phoneNumber });

      return response.data;
    } catch (error) {
      logger.error('Error sending message', {
        instanceName,
        phoneNumber,
        error: error.message,
        response: error.response?.data
      });
      throw new Error(`Failed to send message: ${error.response?.data?.message || error.message}`);
    }
  }

  /**
   * Send reaction to a message
   * @param {string} instanceName - Instance name
   * @param {Object} messageKey - Message key object from Evolution API
   * @param {string} emoji - Emoji to react with
   * @returns {Promise<Object>} Send result
   */
  async sendReaction(instanceName, messageKey, emoji) {
    try {
      logger.info('Sending reaction via Evolution API', { instanceName, emoji });

      const client = this.getClient();
      const response = await client.post(`/message/sendReaction/${instanceName}`, {
        key: messageKey,
        reaction: emoji
      });

      logger.info('Reaction sent successfully', { instanceName, emoji });

      return response.data;
    } catch (error) {
      logger.error('Error sending reaction', {
        instanceName,
        emoji,
        error: error.message,
        response: error.response?.data
      });
      throw new Error(`Failed to send reaction: ${error.response?.data?.message || error.message}`);
    }
  }

  /**
   * Send media message
   * @param {string} instanceName - Instance name
   * @param {string} phoneNumber - Recipient phone number
   * @param {string} mediaUrl - Media URL
   * @param {string} caption - Media caption
   * @param {string} mediaType - Media type (image, video, audio, document)
   * @returns {Promise<Object>} Send result
   */
  async sendMedia(instanceName, phoneNumber, mediaUrl, caption = '', mediaType = 'image') {
    try {
      logger.info('Sending media via Evolution API', { instanceName, phoneNumber, mediaType });

      // Format phone number
      const formattedPhone = phoneNumber.replace(/^\+/, '').replace('@s.whatsapp.net', '').replace('@lid', '');

      let endpoint = '/message/sendMedia';
      const payload = {
        number: formattedPhone,
        mediatype: mediaType,
        media: mediaUrl
      };

      if (caption) {
        payload.caption = caption;
      }

      const client = this.getClient();
      const response = await client.post(`${endpoint}/${instanceName}`, payload);

      logger.info('Media sent successfully', { instanceName, phoneNumber, mediaType });

      return response.data;
    } catch (error) {
      logger.error('Error sending media', {
        instanceName,
        phoneNumber,
        mediaType,
        error: error.message,
        response: error.response?.data
      });
      throw new Error(`Failed to send media: ${error.response?.data?.message || error.message}`);
    }
  }

  /**
   * Send interactive message with CTA button
   * @param {string} instanceName - Instance name
   * @param {string} phoneNumber - Recipient phone number
   * @param {string} bodyText - Message body text
   * @param {string} buttonText - Button display text
   * @param {string} buttonUrl - Button URL
   * @param {string} footerText - Optional footer text
   * @returns {Promise<Object>} Send result
   */
  async sendButtonMessage(instanceName, phoneNumber, bodyText, buttonText, buttonUrl, footerText = '') {
    try {
      logger.info('Sending button message via Evolution API', { instanceName, phoneNumber });

      // Format phone number
      const formattedPhone = phoneNumber.replace(/^\+/, '').replace('@s.whatsapp.net', '').replace('@lid', '');

      const payload = {
        number: formattedPhone,
        options: {
          delay: 1200,
          presence: 'composing'
        },
        buttonMessage: {
          text: bodyText,
          buttons: [
            {
              type: 'url',
              displayText: buttonText,
              url: buttonUrl
            }
          ],
          footerText: footerText || undefined
        }
      };

      const client = this.getClient();
      const response = await client.post(`/message/sendButtons/${instanceName}`, payload);

      logger.info('Button message sent successfully', { instanceName, phoneNumber });

      return response.data;
    } catch (error) {
      logger.error('Error sending button message', {
        instanceName,
        phoneNumber,
        error: error.message,
        response: error.response?.data
      });
      // If button message fails, return null so we can fallback to text message
      logger.warn('Button message failed, will fallback to text message');
      return null;
    }
  }

  /**
   * Get QR code
   * @param {string} instanceName - Instance name
   * @returns {Promise<Object>} QR code data
   */
  async getQRCode(instanceName) {
    try {
      const client = this.getClient();
      
      logger.info('Requesting QR code from Evolution API', { 
        instanceName,
        url: `/instance/qrcode/${instanceName}`,
        baseURL: process.env.EVOLUTION_API_URL
      });
      
      const response = await client.get(`/instance/qrcode/${instanceName}`);

      logger.info('QR code response received', { 
        instanceName,
        hasData: !!response.data,
        dataKeys: response.data ? Object.keys(response.data) : [],
        fullData: response.data
      });

      return response.data;
    } catch (error) {
      logger.error('Error getting QR code from Evolution API', {
        instanceName,
        error: error.message,
        status: error.response?.status,
        statusText: error.response?.statusText,
        responseData: error.response?.data,
        url: error.config?.url,
        baseURL: error.config?.baseURL
      });
      throw new Error(`Failed to get QR code: ${error.response?.data?.message || error.message}`);
    }
  }

  /**
   * Restart instance
   * @param {string} instanceName - Instance name
   * @returns {Promise<Object>} Restart result
   */
  async restartInstance(instanceName) {
    try {
      logger.info('Restarting instance', { instanceName });

      const client = this.getClient();
      const response = await client.put(`/instance/restart/${instanceName}`);

      logger.info('Instance restarted', { instanceName });

      return response.data;
    } catch (error) {
      logger.error('Error restarting instance', {
        instanceName,
        error: error.message,
        response: error.response?.data
      });
      throw new Error(`Failed to restart: ${error.response?.data?.message || error.message}`);
    }
  }

  /**
   * Get instance info
   * @param {string} instanceName - Instance name
   * @returns {Promise<Object>} Instance info
   */
  async getInstanceInfo(instanceName) {
    try {
      logger.info('Getting instance info from Evolution API', { instanceName });
      
      const client = this.getClient();
      const response = await client.get(`/instance/fetchInstances/${instanceName}`);

      logger.info('Instance info retrieved', { 
        instanceName,
        hasProfilePic: !!response.data?.profilePicUrl,
        profileName: response.data?.profileName
      });

      return response.data;
    } catch (error) {
      logger.error('Error getting instance info', {
        instanceName,
        error: error.message,
        response: error.response?.data
      });
      throw new Error(`Failed to get instance info: ${error.response?.data?.message || error.message}`);
    }
  }

  /**
   * Get instance settings
   * @param {string} instanceName - Instance name
   * @returns {Promise<Object>} Instance settings
   */
  async getInstanceSettings(instanceName) {
    try {
      logger.info('Getting instance settings', { instanceName });

      const client = this.getClient();
      const response = await client.get(`/settings/find/${instanceName}`);

      logger.info('Instance settings retrieved', { instanceName, settings: response.data });

      return response.data;
    } catch (error) {
      logger.error('Error getting instance settings', {
        instanceName,
        error: error.message,
        response: error.response?.data
      });
      throw new Error(`Failed to get settings: ${error.response?.data?.message || error.message}`);
    }
  }

  /**
   * Set instance settings
   * @param {string} instanceName - Instance name
   * @param {Object} settings - Settings object
   * @returns {Promise<Object>} Updated settings
   */
  async setInstanceSettings(instanceName, settings) {
    try {
      logger.info('Setting instance settings', { instanceName, settings });

      const client = this.getClient();
      const response = await client.post(`/settings/set/${instanceName}`, settings);

      logger.info('Instance settings updated', { instanceName });

      return response.data;
    } catch (error) {
      logger.error('Error setting instance settings', {
        instanceName,
        error: error.message,
        response: error.response?.data
      });
      throw new Error(`Failed to set settings: ${error.response?.data?.message || error.message}`);
    }
  }

  /**
   * Fetch profile picture URL for a contact
   * @param {string} instanceName - Instance name
   * @param {string} phoneNumber - Contact phone number (with country code)
   * @returns {Promise<string|null>} Profile picture URL or null
   */
  async fetchProfilePicture(instanceName, phoneNumber) {
    try {
      logger.info('Fetching profile picture from Evolution API', { instanceName, phoneNumber });
      
      const client = this.getClient();
      
      // Format phone number - remove @ suffix if present
      let cleanNumber = phoneNumber;
      if (cleanNumber.includes('@')) {
        cleanNumber = cleanNumber.split('@')[0];
      }
      
      // Evolution API endpoint: GET /chat/fetchProfilePictureUrl/:instanceName
      // Body: { number: "5511999999999" }
      try {
        const response = await client.post(`/chat/fetchProfilePictureUrl/${instanceName}`, {
          number: cleanNumber
        });

        const profilePicUrl = response.data?.profilePictureUrl || response.data?.url || response.data?.picture || null;
        
        if (profilePicUrl) {
          logger.info('Profile picture fetched successfully', { 
            instanceName, 
            phoneNumber: cleanNumber,
            url: profilePicUrl.substring(0, 80) + '...'
          });
          return profilePicUrl;
        }
      } catch (postError) {
        logger.debug('POST method failed, trying GET', { error: postError.message });
      }
      
      // Try GET method as fallback
      try {
        const response = await client.get(`/chat/fetchProfilePictureUrl/${instanceName}`, {
          params: {
            number: cleanNumber
          }
        });

        const profilePicUrl = response.data?.profilePictureUrl || response.data?.url || response.data?.picture || null;
        
        if (profilePicUrl) {
          logger.info('Profile picture fetched successfully via GET', { 
            instanceName, 
            phoneNumber: cleanNumber,
            url: profilePicUrl.substring(0, 80) + '...'
          });
          return profilePicUrl;
        }
      } catch (getError) {
        logger.debug('GET method also failed', { error: getError.message });
      }

      logger.info('No profile picture found for contact', { instanceName, phoneNumber: cleanNumber });
      return null;
      
    } catch (error) {
      logger.warn('Could not fetch profile picture', {
        instanceName,
        phoneNumber,
        error: error.message,
        status: error.response?.status,
        responseData: error.response?.data
      });
      return null;
    }
  }
}

module.exports = new EvolutionAPIService();
