#!/usr/bin/env node

/**
 * Direct connection test to Omada Controller
 * Uses Node.js https module directly for better SSL control
 */

import https from 'https';
import { readFileSync } from 'fs';
import { join } from 'path';
import { homedir } from 'os';

// Load environment variables
const envPath = join(homedir(), '.env');
let envVars = {};

try {
  const envFile = readFileSync(envPath, 'utf8');
  envFile.split('\n').forEach(line => {
    if (line.includes('=') && !line.trim().startsWith('#')) {
      const [key, ...values] = line.split('=');
      if (key && /^[A-Z_][A-Z0-9_]*$/.test(key.trim())) {
        let value = values.join('=').trim();
        if ((value.startsWith('"') && value.endsWith('"')) || 
            (value.startsWith("'") && value.endsWith("'"))) {
          value = value.slice(1, -1);
        }
        envVars[key.trim()] = value;
      }
    }
  });
} catch (error) {
  console.error('Error loading .env file:', error.message);
  process.exit(1);
}

const baseUrl = envVars.OMADA_CONTROLLER_URL || 'https://192.168.11.8:8043';
const username = envVars.OMADA_ADMIN_USERNAME || envVars.OMADA_API_KEY;
const password = envVars.OMADA_ADMIN_PASSWORD || envVars.OMADA_API_SECRET;
const siteId = envVars.OMADA_SITE_ID;
const verifySSL = envVars.OMADA_VERIFY_SSL !== 'false';

if (!username || !password) {
  console.error('Error: Missing credentials');
  console.error('Required: OMADA_ADMIN_USERNAME/OMADA_API_KEY and OMADA_ADMIN_PASSWORD/OMADA_API_SECRET');
  process.exit(1);
}

// Parse base URL
const urlObj = new URL(baseUrl);
const hostname = urlObj.hostname;
const port = urlObj.port || (urlObj.protocol === 'https:' ? 443 : 80);

console.log('=== Omada Controller Direct Connection Test ===\n');
console.log(`Controller URL: ${baseUrl}`);
console.log(`Hostname: ${hostname}`);
console.log(`Port: ${port}`);
console.log(`Site ID: ${siteId || 'auto-detect'}`);
console.log(`SSL Verification: ${verifySSL}\n`);

// Create HTTPS agent
const agent = new https.Agent({
  rejectUnauthorized: verifySSL,
});

// Function to make API request
function apiRequest(method, path, data = null, token = null) {
  return new Promise((resolve, reject) => {
    const options = {
      hostname,
      port,
      path,
      method,
      agent,
      headers: {
        'Content-Type': 'application/json',
      },
    };

    if (token) {
      options.headers['Authorization'] = `Bearer ${token}`;
    }

    const req = https.request(options, (res) => {
      let body = '';
      res.on('data', (chunk) => {
        body += chunk;
      });
      res.on('end', () => {
        try {
          const json = JSON.parse(body);
          if (res.statusCode >= 200 && res.statusCode < 300) {
            resolve(json);
          } else {
            reject(new Error(`HTTP ${res.statusCode}: ${body}`));
          }
        } catch (e) {
          resolve({ raw: body, statusCode: res.statusCode });
        }
      });
    });

    req.on('error', (error) => {
      reject(error);
    });

    if (data) {
      req.write(JSON.stringify(data));
    }
    req.end();
  });
}

async function test() {
  try {
    console.log('1. Testing login...');
    const loginResponse = await apiRequest('POST', '/api/v2/login', {
      username,
      password,
    });
    
    if (loginResponse.errorCode !== 0) {
      console.error(`   ✗ Login failed: ${loginResponse.msg || 'Unknown error'}`);
      console.error(`   Error Code: ${loginResponse.errorCode}`);
      process.exit(1);
    }

    const token = loginResponse.result?.token || loginResponse.token;
    if (!token) {
      console.error('   ✗ No token received');
      process.exit(1);
    }

    console.log('   ✓ Login successful');
    console.log(`   Token: ${token.substring(0, 20)}...\n`);

    console.log('2. Getting site information...');
    // Try different endpoint formats
    let sitesResponse;
    try {
      sitesResponse = await apiRequest('GET', '/api/v2/sites', null, token);
    } catch (e) {
      // If redirect, try with omadacId parameter
      try {
        sitesResponse = await apiRequest('GET', `/api/v2/sites?omadacId=${siteId}`, null, token);
      } catch (e2) {
        console.log('   Note: Sites endpoint may require different format');
        sitesResponse = { errorCode: -1, msg: 'Could not query sites endpoint' };
      }
    }
    
    if (sitesResponse.errorCode === 0 && sitesResponse.result) {
      const sites = Array.isArray(sitesResponse.result) ? sitesResponse.result : [];
      console.log(`   ✓ Found ${sites.length} site(s)`);
      sites.forEach((site, index) => {
        console.log(`   Site ${index + 1}: ${site.name} (${site.id})`);
        if (site.id === siteId) {
          console.log(`      ^ Using this site`);
        }
      });
    } else if (sitesResponse.statusCode === 302 || sitesResponse.raw === '') {
      console.log('   Note: Sites endpoint returned redirect (may require web interface)');
      console.log(`   Using provided site ID: ${siteId}`);
    } else {
      console.log('   Response:', JSON.stringify(sitesResponse, null, 2));
    }
    console.log('');

    const effectiveSiteId = siteId || (sitesResponse.result?.[0]?.id);
    if (effectiveSiteId) {
      console.log(`3. Using site ID: ${effectiveSiteId}\n`);

      console.log('4. Listing devices...');
      let devicesResponse;
      try {
        devicesResponse = await apiRequest('GET', `/api/v2/sites/${effectiveSiteId}/devices`, null, token);
      } catch (e) {
        try {
          devicesResponse = await apiRequest('GET', `/api/v2/sites/${effectiveSiteId}/devices?omadacId=${effectiveSiteId}`, null, token);
        } catch (e2) {
          devicesResponse = { errorCode: -1, msg: 'Could not query devices endpoint' };
        }
      }
      
      if (devicesResponse.errorCode === 0 && devicesResponse.result) {
        const devices = Array.isArray(devicesResponse.result) ? devicesResponse.result : [];
        console.log(`   ✓ Found ${devices.length} device(s)`);
        
        if (devices.length > 0) {
          console.log('\n   Devices:');
          
          const routers = devices.filter(d => d.type === 'router' || d.type === 'Gateway');
          const switches = devices.filter(d => d.type === 'switch' || d.type === 'Switch');
          const aps = devices.filter(d => d.type === 'ap' || d.type === 'AccessPoint');
          
          if (routers.length > 0) {
            console.log('\n   ROUTERS:');
            routers.forEach((device, index) => {
              const status = device.status === 1 ? '🟢 Online' : device.status === 0 ? '🔴 Offline' : '🟡 Unknown';
              console.log(`   ${index + 1}. ${device.name || device.mac || 'Unknown'}`);
              console.log(`      Model: ${device.model || 'N/A'}`);
              console.log(`      Status: ${status}`);
              console.log(`      IP: ${device.ip || 'N/A'}`);
              console.log(`      MAC: ${device.mac || 'N/A'}`);
              console.log(`      Device ID: ${device.id || 'N/A'}`);
              console.log('');
            });
          }
          
          if (switches.length > 0) {
            console.log('\n   SWITCHES:');
            switches.forEach((device, index) => {
              const status = device.status === 1 ? '🟢 Online' : device.status === 0 ? '🔴 Offline' : '🟡 Unknown';
              console.log(`   ${index + 1}. ${device.name || device.mac || 'Unknown'}`);
              console.log(`      Model: ${device.model || 'N/A'}`);
              console.log(`      Status: ${status}`);
              console.log(`      IP: ${device.ip || 'N/A'}`);
              console.log(`      MAC: ${device.mac || 'N/A'}`);
              console.log(`      Device ID: ${device.id || 'N/A'}`);
              console.log('');
            });
          }
          
          if (aps.length > 0) {
            console.log('\n   ACCESS POINTS:');
            aps.forEach((device, index) => {
              const status = device.status === 1 ? '🟢 Online' : device.status === 0 ? '🔴 Offline' : '🟡 Unknown';
              console.log(`   ${index + 1}. ${device.name || device.mac || 'Unknown'}`);
              console.log(`      Model: ${device.model || 'N/A'}`);
              console.log(`      Status: ${status}`);
              console.log(`      IP: ${device.ip || 'N/A'}`);
              console.log('');
            });
          }
          
          const others = devices.filter(d => 
            d.type !== 'router' && d.type !== 'Gateway' && 
            d.type !== 'switch' && d.type !== 'Switch' && 
            d.type !== 'ap' && d.type !== 'AccessPoint'
          );
          
          if (others.length > 0) {
            console.log('\n   OTHER DEVICES:');
            others.forEach((device, index) => {
              const status = device.status === 1 ? '🟢 Online' : device.status === 0 ? '🔴 Offline' : '🟡 Unknown';
              console.log(`   ${index + 1}. ${device.name || device.mac || 'Unknown'} (${device.type || 'Unknown'})`);
              console.log(`      Status: ${status}`);
              console.log(`      IP: ${device.ip || 'N/A'}`);
              console.log('');
            });
          }
        } else {
          console.log('   No devices found');
        }
      } else if (devicesResponse.statusCode === 302 || devicesResponse.raw === '') {
        console.log('   Note: Devices endpoint returned redirect (API may require different format)');
        console.log('   Try accessing web interface at https://192.168.11.8:8043 to view devices');
      } else {
        console.log('   Response:', JSON.stringify(devicesResponse, null, 2));
      }

      console.log('5. Listing VLANs...');
      const vlansResponse = await apiRequest('GET', `/api/v2/sites/${effectiveSiteId}/vlans`, null, token);
      
      if (vlansResponse.errorCode === 0 && vlansResponse.result) {
        const vlans = Array.isArray(vlansResponse.result) ? vlansResponse.result : [];
        console.log(`   ✓ Found ${vlans.length} VLAN(s)`);
        
        if (vlans.length > 0) {
          console.log('\n   VLANs:');
          vlans.forEach((vlan, index) => {
            console.log(`   ${index + 1}. VLAN ${vlan.vlanId || 'N/A'}: ${vlan.name || 'Unnamed'}`);
            if (vlan.subnet) console.log(`      Subnet: ${vlan.subnet}`);
            if (vlan.gateway) console.log(`      Gateway: ${vlan.gateway}`);
            console.log('');
          });
        } else {
          console.log('   No VLANs configured');
        }
      } else {
        console.log('   Response:', JSON.stringify(vlansResponse, null, 2));
      }
    }

    console.log('\n=== Connection test completed successfully! ===');
    
  } catch (error) {
    console.error('\n=== Test failed ===');
    console.error('Error:', error.message);
    if (error.stack) {
      console.error('\nStack trace:');
      console.error(error.stack);
    }
    process.exit(1);
  }
}

test();

