const axios = require('axios');
const { exec } = require('child_process');
const { promisify } = require('util');
const fs = require('fs').promises;

const execAsync = promisify(exec);

/**
 * VPN Diagnostics - Check for IP and DNS leaks
 */
class VPNDiagnostics {
  /**
   * Get current public IP address
   */
  static async getPublicIP() {
    try {
      const response = await axios.get('https://api.ipify.org?format=json', { 
        timeout: 10000,
        validateStatus: () => true 
      });
      return response.data.ip;
    } catch (error) {
      throw new Error(`Failed to get public IP: ${error.message}`);
    }
  }

  /**
   * Get detailed IP information (location, ISP, etc.)
   */
  static async getIPInfo(ip) {
    try {
      const response = await axios.get(`https://ipinfo.io/${ip || ''}/json`, { 
        timeout: 10000,
        validateStatus: () => true 
      });
      return response.data;
    } catch (error) {
      console.warn('Could not get IP info:', error.message);
      return null;
    }
  }

  /**
   * Get current DNS servers from resolv.conf
   */
  static async getDNSServers() {
    try {
      const resolvConf = await fs.readFile('/etc/resolv.conf', 'utf8');
      const nameservers = resolvConf
        .split('\n')
        .filter(line => line.trim().startsWith('nameserver'))
        .map(line => line.split(/\s+/)[1]);
      
      return nameservers;
    } catch (error) {
      throw new Error(`Failed to read DNS servers: ${error.message}`);
    }
  }

  /**
   * Check if VPN interface (tun) exists
   */
  static async checkVPNInterface() {
    try {
      const { stdout } = await execAsync('ip addr show tun0 2>/dev/null');
      return {
        exists: true,
        details: stdout.trim()
      };
    } catch (error) {
      return {
        exists: false,
        details: null
      };
    }
  }

  /**
   * Get routing table
   */
  static async getRoutingTable() {
    try {
      const { stdout } = await execAsync('ip route');
      return stdout.trim().split('\n');
    } catch (error) {
      throw new Error(`Failed to get routing table: ${error.message}`);
    }
  }

  /**
   * Test DNS resolution through current DNS servers
   */
  static async testDNSResolution(domain = 'google.com') {
    try {
      const { stdout } = await execAsync(`nslookup ${domain} | grep -A1 "Name:" | tail -1`);
      return {
        success: true,
        result: stdout.trim()
      };
    } catch (error) {
      return {
        success: false,
        error: error.message
      };
    }
  }

  /**
   * Check for DNS leaks by testing against multiple DNS leak test services
   */
  static async checkDNSLeaks() {
    const dnsServers = await this.getDNSServers();
    
    // Check if DNS servers are common VPN DNS servers
    const commonVPNDNS = ['10.2.0.1', '10.2.0.2', '10.8.0.1', '10.0.0.1'];
    const isUsingVPNDNS = dnsServers.some(dns => commonVPNDNS.includes(dns) || dns.startsWith('10.'));
    
    // Check if DNS servers match common public DNS (potential leak)
    const commonPublicDNS = [
      '8.8.8.8', '8.8.4.4',  // Google
      '1.1.1.1', '1.0.0.1',  // Cloudflare
      '9.9.9.9',             // Quad9
    ];
    const isUsingPublicDNS = dnsServers.some(dns => commonPublicDNS.includes(dns));
    
    return {
      dnsServers,
      isUsingVPNDNS,
      isUsingPublicDNS,
      potentialLeak: !isUsingVPNDNS && isUsingPublicDNS
    };
  }

  /**
   * Run comprehensive VPN diagnostics
   */
  static async runFullDiagnostics() {
    console.log('🔍 Running VPN diagnostics...');
    
    const results = {
      timestamp: new Date().toISOString(),
      publicIP: null,
      ipInfo: null,
      dnsServers: [],
      vpnInterface: null,
      routingTable: [],
      dnsLeakCheck: null,
      summary: {
        vpnActive: false,
        ipLeak: false,
        dnsLeak: false,
        issues: []
      }
    };

    try {
      // Get public IP
      results.publicIP = await this.getPublicIP();
      console.log(`✓ Public IP: ${results.publicIP}`);

      // Get IP info
      results.ipInfo = await this.getIPInfo(results.publicIP);
      if (results.ipInfo) {
        console.log(`✓ Location: ${results.ipInfo.city}, ${results.ipInfo.country}`);
        console.log(`✓ ISP: ${results.ipInfo.org}`);
      }

      // Get DNS servers
      results.dnsServers = await this.getDNSServers();
      console.log(`✓ DNS Servers: ${results.dnsServers.join(', ')}`);

      // Check VPN interface
      results.vpnInterface = await this.checkVPNInterface();
      if (results.vpnInterface.exists) {
        console.log('✓ VPN interface (tun0) is UP');
        results.summary.vpnActive = true;
      } else {
        console.log('✗ VPN interface (tun0) NOT found');
        results.summary.issues.push('VPN interface not found');
      }

      // Get routing table
      results.routingTable = await this.getRoutingTable();
      const defaultRoute = results.routingTable.find(route => route.startsWith('default'));
      if (defaultRoute) {
        console.log(`✓ Default route: ${defaultRoute}`);
        if (defaultRoute.includes('tun')) {
          console.log('✓ Traffic is routed through VPN');
        } else {
          console.log('✗ Traffic NOT routed through VPN');
          results.summary.ipLeak = true;
          results.summary.issues.push('Traffic not routed through VPN interface');
        }
      }

      // DNS leak check
      results.dnsLeakCheck = await this.checkDNSLeaks();
      if (results.dnsLeakCheck.isUsingVPNDNS) {
        console.log('✓ Using VPN DNS servers');
      } else if (results.dnsLeakCheck.potentialLeak) {
        console.log('✗ Potential DNS leak detected');
        results.summary.dnsLeak = true;
        results.summary.issues.push('Using non-VPN DNS servers');
      }

      // Overall status
      if (results.summary.vpnActive && !results.summary.ipLeak && !results.summary.dnsLeak) {
        console.log('\n✓ VPN is working correctly - No leaks detected');
      } else {
        console.log('\n✗ VPN issues detected:');
        results.summary.issues.forEach(issue => console.log(`  - ${issue}`));
      }

    } catch (error) {
      console.error('Error during diagnostics:', error);
      results.summary.issues.push(error.message);
    }

    return results;
  }

  /**
   * Quick check if VPN is working (used by status endpoint)
   */
  static async quickCheck() {
    try {
      const [publicIP, dnsServers, vpnInterface] = await Promise.all([
        this.getPublicIP(),
        this.getDNSServers(),
        this.checkVPNInterface()
      ]);

      return {
        publicIP,
        dnsServers,
        vpnInterfaceActive: vpnInterface.exists,
        timestamp: new Date().toISOString()
      };
    } catch (error) {
      throw new Error(`Quick check failed: ${error.message}`);
    }
  }
}

module.exports = VPNDiagnostics;
