/**
 * HTTP Utility for Node.js environments
 * 
 * Handles HTTP requests with fallback from curl to built-in http module
 */

const { exec } = require('child_process');
const util = require('util');
const http = require('http');
const execAsync = util.promisify(exec);

class HttpUtil {
  static curlAvailable = null;

  static async checkCurlAvailability() {
    if (this.curlAvailable !== null) {
      return this.curlAvailable;
    }

    try {
      await execAsync('which curl');
      this.curlAvailable = true;
      return true;
    } catch (error) {
      this.curlAvailable = false;
      return false;
    }
  }

  static async get(url) {
    const isCurlAvailable = await this.checkCurlAvailability();

    if (isCurlAvailable) {
      return this.getWithCurl(url);
    } else {
      return this.getWithHttp(url);
    }
  }

  static async getWithCurl(url) {
    try {
      const { stdout } = await execAsync(`curl -s ${url}`);
      return JSON.parse(stdout);
    } catch (error) {
      throw new Error(`curl request failed: ${error.message}`);
    }
  }

  static async getWithHttp(url) {
    return new Promise((resolve, reject) => {
      const urlObj = new URL(url);
      
      const req = http.get({
        hostname: urlObj.hostname,
        port: urlObj.port || 80,
        path: urlObj.pathname + urlObj.search,
        timeout: 5000
      }, (res) => {
        let data = '';
        
        res.on('data', (chunk) => {
          data += chunk;
        });
        
        res.on('end', () => {
          try {
            const parsedData = JSON.parse(data);
            resolve(parsedData);
          } catch (parseError) {
            reject(new Error(`JSON parse error: ${parseError.message}`));
          }
        });
      });

      req.on('error', (error) => {
        reject(new Error(`HTTP request error: ${error.message}`));
      });

      req.on('timeout', () => {
        req.destroy();
        reject(new Error('Request timeout'));
      });
    });
  }

  static async post(url, data) {
    const isCurlAvailable = await this.checkCurlAvailability();

    if (isCurlAvailable) {
      return this.postWithCurl(url, data);
    } else {
      return this.postWithHttp(url, data);
    }
  }

  static async postWithCurl(url, data) {
    try {
      const jsonData = JSON.stringify(data);
      const { stdout } = await execAsync(`curl -s -X POST -H "Content-Type: application/json" -d '${jsonData}' ${url}`);
      return JSON.parse(stdout);
    } catch (error) {
      throw new Error(`curl POST request failed: ${error.message}`);
    }
  }

  static async postWithHttp(url, data) {
    return new Promise((resolve, reject) => {
      const urlObj = new URL(url);
      const postData = JSON.stringify(data);
      
      const options = {
        hostname: urlObj.hostname,
        port: urlObj.port || 80,
        path: urlObj.pathname + urlObj.search,
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'Content-Length': Buffer.byteLength(postData)
        },
        timeout: 5000
      };

      const req = http.request(options, (res) => {
        let responseData = '';
        
        res.on('data', (chunk) => {
          responseData += chunk;
        });
        
        res.on('end', () => {
          try {
            const parsedData = JSON.parse(responseData);
            resolve(parsedData);
          } catch (parseError) {
            reject(new Error(`JSON parse error: ${parseError.message}`));
          }
        });
      });

      req.on('error', (error) => {
        reject(new Error(`HTTP request error: ${error.message}`));
      });

      req.on('timeout', () => {
        req.destroy();
        reject(new Error('Request timeout'));
      });

      req.write(postData);
      req.end();
    });
  }
}

module.exports = HttpUtil;
