import { execSync } from 'child_process';
import { Nupst } from '../nupst.js';
import { logger } from '../logger.js';
import * as helpers from '../helpers/index.js';

/**
 * Class for handling UPS-related CLI commands
 * Provides interface for managing UPS devices
 */
export class UpsHandler {
  private readonly nupst: Nupst;

  /**
   * Create a new UPS handler
   * @param nupst Reference to the main Nupst instance
   */
  constructor(nupst: Nupst) {
    this.nupst = nupst;
  }

  /**
   * Add a new UPS configuration
   */
  public async add(): Promise<void> {
    try {
      // Import readline module for user input
      const readline = await import('readline');

      const rl = readline.createInterface({
        input: process.stdin,
        output: process.stdout,
      });

      // Helper function to prompt for input
      const prompt = (question: string): Promise<string> => {
        return new Promise((resolve) => {
          rl.question(question, (answer: string) => {
            resolve(answer);
          });
        });
      };

      try {
        await this.runAddProcess(prompt);
      } finally {
        rl.close();
      }
    } catch (error) {
      logger.error(`Add UPS error: ${error.message}`);
    }
  }

  /**
   * Run the interactive process to add a new UPS
   * @param prompt Function to prompt for user input
   */
  public async runAddProcess(prompt: (question: string) => Promise<string>): Promise<void> {
    logger.log('\nNUPST Add UPS');
    logger.log('=============\n');
    logger.log('This will guide you through configuring a new UPS.\n');

    // Try to load existing config if available
    let config;
    try {
      await this.nupst.getDaemon().loadConfig();
      config = this.nupst.getDaemon().getConfig();
      
      // Convert old format to new format if needed
      if (!config.upsDevices) {
        // Initialize with the current config as the first UPS
        config = {
          checkInterval: config.checkInterval,
          upsDevices: [{
            id: 'default',
            name: 'Default UPS',
            snmp: config.snmp,
            thresholds: config.thresholds,
            groups: []
          }],
          groups: []
        };
        logger.log('Converting existing configuration to multi-UPS format.');
      }
    } catch (error) {
      // If config doesn't exist, initialize with empty config
      config = {
        checkInterval: 30000, // Default check interval
        upsDevices: [],
        groups: []
      };
      logger.log('No existing configuration found. Creating a new configuration.');
    }

    // Get UPS ID and name
    const upsId = helpers.shortId();
    const name = await prompt('UPS Name: ');

    // Create a new UPS configuration object with defaults
    const newUps = {
      id: upsId,
      name: name || `UPS-${upsId}`,
      snmp: {
        host: '127.0.0.1',
        port: 161,
        community: 'public',
        version: 1,
        timeout: 5000,
        upsModel: 'cyberpower'
      },
      thresholds: {
        battery: 60,
        runtime: 20
      },
      groups: []
    };

    // Gather SNMP settings
    await this.gatherSnmpSettings(newUps.snmp, prompt);

    // Gather threshold settings
    await this.gatherThresholdSettings(newUps.thresholds, prompt);

    // Gather UPS model settings
    await this.gatherUpsModelSettings(newUps.snmp, prompt);

    // Get access to GroupHandler for group assignments
    const groupHandler = this.nupst.getGroupHandler();

    // Assign to groups if any exist
    if (config.groups && config.groups.length > 0) {
      await groupHandler.assignUpsToGroups(newUps, config.groups, prompt);
    }

    // Add the new UPS to the config
    config.upsDevices.push(newUps);

    // Save the configuration
    await this.nupst.getDaemon().saveConfig(config);

    this.displayUpsConfigSummary(newUps);

    // Test the connection if requested
    await this.optionallyTestConnection(newUps.snmp, prompt);
    
    // Check if service is running and restart it if needed
    await this.restartServiceIfRunning();
    
    logger.log('\nSetup complete!');
  }

  /**
   * Edit an existing UPS configuration
   * @param upsId ID of the UPS to edit (undefined for default UPS)
   */
  public async edit(upsId?: string): Promise<void> {
    try {
      // Import readline module for user input
      const readline = await import('readline');

      const rl = readline.createInterface({
        input: process.stdin,
        output: process.stdout,
      });

      // Helper function to prompt for input
      const prompt = (question: string): Promise<string> => {
        return new Promise((resolve) => {
          rl.question(question, (answer: string) => {
            resolve(answer);
          });
        });
      };

      try {
        await this.runEditProcess(upsId, prompt);
      } finally {
        rl.close();
      }
    } catch (error) {
      logger.error(`Edit UPS error: ${error.message}`);
    }
  }

  /**
   * Run the interactive process to edit a UPS
   * @param upsId ID of the UPS to edit (undefined for default UPS)
   * @param prompt Function to prompt for user input
   */
  public async runEditProcess(upsId: string | undefined, prompt: (question: string) => Promise<string>): Promise<void> {
    logger.log('\nNUPST Edit UPS');
    logger.log('=============\n');
    
    // Try to load existing config
    try {
      await this.nupst.getDaemon().loadConfig();
    } catch (error) {
      if (!upsId) {
        // For default UPS (no ID specified), run setup if no config exists
        logger.log('No existing configuration found. Running setup for new UPS.');
        await this.runAddProcess(prompt);
        return;
      } else {
        // For specific UPS ID, error if config doesn't exist
        logger.error('No configuration found. Please run "nupst setup" first.');
        return;
      }
    }
    
    // Get the config
    const config = this.nupst.getDaemon().getConfig();
    
    // Convert old format to new format if needed
    if (!config.upsDevices) {
      // Initialize with the current config as the first UPS
      config.upsDevices = [{
        id: 'default',
        name: 'Default UPS',
        snmp: config.snmp,
        thresholds: config.thresholds,
        groups: []
      }];
      config.groups = [];
      logger.log('Converting existing configuration to multi-UPS format.');
    }
    
    // Find the UPS to edit
    let upsToEdit;
    if (upsId) {
      // Find specific UPS by ID
      upsToEdit = config.upsDevices.find(ups => ups.id === upsId);
      if (!upsToEdit) {
        logger.error(`UPS with ID "${upsId}" not found.`);
        return;
      }
      logger.log(`Editing UPS: ${upsToEdit.name} (${upsToEdit.id})\n`);
    } else {
      // For backward compatibility, edit the first UPS if no ID specified
      if (config.upsDevices.length === 0) {
        logger.error('No UPS devices configured. Please run "nupst add" to add a UPS.');
        return;
      }
      upsToEdit = config.upsDevices[0];
      logger.log(`Editing default UPS: ${upsToEdit.name} (${upsToEdit.id})\n`);
    }
    
    // Allow editing UPS name
    const newName = await prompt(`UPS Name [${upsToEdit.name}]: `);
    if (newName.trim()) {
      upsToEdit.name = newName;
    }
    
    // Edit SNMP settings
    await this.gatherSnmpSettings(upsToEdit.snmp, prompt);
    
    // Edit threshold settings
    await this.gatherThresholdSettings(upsToEdit.thresholds, prompt);
    
    // Edit UPS model settings
    await this.gatherUpsModelSettings(upsToEdit.snmp, prompt);
    
    // Get access to GroupHandler for group assignments
    const groupHandler = this.nupst.getGroupHandler();
    
    // Edit group assignments
    if (config.groups && config.groups.length > 0) {
      await groupHandler.assignUpsToGroups(upsToEdit, config.groups, prompt);
    }
    
    // Save the configuration
    await this.nupst.getDaemon().saveConfig(config);
    
    this.displayUpsConfigSummary(upsToEdit);
    
    // Test the connection if requested
    await this.optionallyTestConnection(upsToEdit.snmp, prompt);
    
    // Check if service is running and restart it if needed
    await this.restartServiceIfRunning();
    
    logger.log('\nEdit complete!');
  }

  /**
   * Delete a UPS by ID
   * @param upsId ID of the UPS to delete
   */
  public async delete(upsId: string): Promise<void> {
    try {
      // Try to load configuration
      try {
        await this.nupst.getDaemon().loadConfig();
      } catch (error) {
        const errorBoxWidth = 45;
        logger.logBoxTitle('Configuration Error', errorBoxWidth);
        logger.logBoxLine('No configuration found.');
        logger.logBoxLine("Please run 'nupst setup' first to create a configuration.");
        logger.logBoxEnd();
        return;
      }
      
      // Get current configuration
      const config = this.nupst.getDaemon().getConfig();
      
      // Check if multi-UPS config
      if (!config.upsDevices || !Array.isArray(config.upsDevices)) {
        logger.error('Legacy single-UPS configuration detected. Cannot delete UPS.');
        logger.log('Use "nupst add" to migrate to multi-UPS configuration format first.');
        return;
      }
      
      // Find the UPS to delete
      const upsIndex = config.upsDevices.findIndex(ups => ups.id === upsId);
      if (upsIndex === -1) {
        logger.error(`UPS with ID "${upsId}" not found.`);
        return;
      }
      
      const upsToDelete = config.upsDevices[upsIndex];
      
      // Get confirmation before deleting
      const readline = await import('readline');
      const rl = readline.createInterface({
        input: process.stdin,
        output: process.stdout,
      });
      
      const confirm = await new Promise<string>(resolve => {
        rl.question(`Are you sure you want to delete UPS "${upsToDelete.name}" (${upsId})? [y/N]: `, answer => {
          resolve(answer.toLowerCase());
        });
      });
      
      rl.close();
      
      if (confirm !== 'y' && confirm !== 'yes') {
        logger.log('Deletion cancelled.');
        return;
      }
      
      // Remove the UPS from the array
      config.upsDevices.splice(upsIndex, 1);
      
      // Save the configuration
      await this.nupst.getDaemon().saveConfig(config);
      
      logger.log(`UPS "${upsToDelete.name}" (${upsId}) has been deleted.`);
      
      // Check if service is running and restart it if needed
      await this.restartServiceIfRunning();
    } catch (error) {
      logger.error(`Failed to delete UPS: ${error.message}`);
    }
  }

  /**
   * List all configured UPS devices
   */
  public async list(): Promise<void> {
    try {
      // Try to load configuration
      try {
        await this.nupst.getDaemon().loadConfig();
      } catch (error) {
        const errorBoxWidth = 45;
        logger.logBoxTitle('Configuration Error', errorBoxWidth);
        logger.logBoxLine('No configuration found.');
        logger.logBoxLine("Please run 'nupst setup' first to create a configuration.");
        logger.logBoxEnd();
        return;
      }
      
      // Get current configuration
      const config = this.nupst.getDaemon().getConfig();
      
      // Check if multi-UPS config
      if (!config.upsDevices || !Array.isArray(config.upsDevices)) {
        // Legacy single UPS configuration
        const boxWidth = 45;
        logger.logBoxTitle('UPS Devices', boxWidth);
        logger.logBoxLine('Legacy single-UPS configuration detected.');
        logger.logBoxLine('');
        logger.logBoxLine('Default UPS:');
        logger.logBoxLine(`  Host: ${config.snmp.host}:${config.snmp.port}`);
        logger.logBoxLine(`  Model: ${config.snmp.upsModel || 'cyberpower'}`);
        logger.logBoxLine(`  Thresholds: ${config.thresholds.battery}% battery, ${config.thresholds.runtime} min runtime`);
        logger.logBoxLine('');
        logger.logBoxLine('Use "nupst add" to add more UPS devices and migrate');
        logger.logBoxLine('to the multi-UPS configuration format.');
        logger.logBoxEnd();
        return;
      }
      
      // Display UPS list
      const boxWidth = 60;
      logger.logBoxTitle('UPS Devices', boxWidth);
      
      if (config.upsDevices.length === 0) {
        logger.logBoxLine('No UPS devices configured.');
        logger.logBoxLine('Use "nupst add" to add a UPS device.');
      } else {
        logger.logBoxLine(`Found ${config.upsDevices.length} UPS device(s)`);
        logger.logBoxLine('');
        logger.logBoxLine('ID          | Name                  | Host            | Mode         | Groups');
        logger.logBoxLine('-----------+----------------------+----------------+--------------+----------------');
        
        for (const ups of config.upsDevices) {
          const id = ups.id.padEnd(10, ' ').substring(0, 10);
          const name = (ups.name || '').padEnd(20, ' ').substring(0, 20);
          const host = `${ups.snmp.host}:${ups.snmp.port}`.padEnd(15, ' ').substring(0, 15);
          const model = (ups.snmp.upsModel || 'cyberpower').padEnd(12, ' ').substring(0, 12);
          const groups = ups.groups.length > 0 ? ups.groups.join(', ') : 'None';
          
          logger.logBoxLine(`${id} | ${name} | ${host} | ${model} | ${groups}`);
        }
      }
      
      logger.logBoxEnd();
    } catch (error) {
      logger.error(`Failed to list UPS devices: ${error.message}`);
    }
  }

  /**
   * Test the current configuration by connecting to the UPS
   * @param debugMode Whether to enable debug mode
   */
  public async test(debugMode: boolean = false): Promise<void> {
    try {
      // Debug mode is now handled in parseAndExecute
      if (debugMode) {
        const boxWidth = 45;
        logger.logBoxTitle('Debug Mode', boxWidth);
        logger.logBoxLine('SNMP debugging enabled - detailed logs will be shown');
        logger.logBoxEnd();
      }

      // Try to load the configuration
      try {
        await this.nupst.getDaemon().loadConfig();
      } catch (error) {
        const errorBoxWidth = 45;
        logger.logBoxTitle('Configuration Error', errorBoxWidth);
        logger.logBoxLine('No configuration found.');
        logger.logBoxLine("Please run 'nupst setup' first to create a configuration.");
        logger.logBoxEnd();
        return;
      }

      // Get current configuration
      const config = this.nupst.getDaemon().getConfig();

      // Handle new multi-UPS configuration format
      if (config.upsDevices && config.upsDevices.length > 0) {
        logger.log(`Found ${config.upsDevices.length} UPS devices in configuration.`);
        
        for (let i = 0; i < config.upsDevices.length; i++) {
          const ups = config.upsDevices[i];
          logger.log(`\nTesting UPS: ${ups.name} (${ups.id})`);
          this.displayTestConfig(ups);
          await this.testConnection(ups);
        }
      } else {
        // Legacy configuration format
        this.displayTestConfig(config);
        await this.testConnection(config);
      }
    } catch (error) {
      logger.error(`Test failed: ${error.message}`);
    }
  }

  /**
   * Display the configuration for testing
   * @param config Current configuration or individual UPS configuration
   */
  private displayTestConfig(config: any): void {
    // Check if this is a UPS device or full configuration
    const isUpsConfig = config.snmp && config.thresholds;
    const snmpConfig = isUpsConfig ? config.snmp : config.snmp || {};
    const thresholds = isUpsConfig ? config.thresholds : config.thresholds || {};
    const checkInterval = config.checkInterval || 30000;
    
    // Get UPS name and ID if available
    const upsName = config.name ? config.name : 'Default UPS';
    const upsId = config.id ? config.id : 'default';
    
    const boxWidth = 45;
    logger.logBoxTitle(`Testing Configuration: ${upsName}`, boxWidth);
    logger.logBoxLine(`UPS ID: ${upsId}`);
    logger.logBoxLine('SNMP Settings:');
    logger.logBoxLine(`  Host: ${snmpConfig.host}`);
    logger.logBoxLine(`  Port: ${snmpConfig.port}`);
    logger.logBoxLine(`  Version: ${snmpConfig.version}`);
    logger.logBoxLine(`  UPS Model: ${snmpConfig.upsModel || 'cyberpower'}`);

    if (snmpConfig.version === 1 || snmpConfig.version === 2) {
      logger.logBoxLine(`  Community: ${snmpConfig.community}`);
    } else if (snmpConfig.version === 3) {
      logger.logBoxLine(`  Security Level: ${snmpConfig.securityLevel}`);
      logger.logBoxLine(`  Username: ${snmpConfig.username}`);

      // Show auth and privacy details based on security level
      if (snmpConfig.securityLevel === 'authNoPriv' || snmpConfig.securityLevel === 'authPriv') {
        logger.logBoxLine(`  Auth Protocol: ${snmpConfig.authProtocol || 'None'}`);
      }

      if (snmpConfig.securityLevel === 'authPriv') {
        logger.logBoxLine(`  Privacy Protocol: ${snmpConfig.privProtocol || 'None'}`);
      }

      // Show timeout value
      logger.logBoxLine(`  Timeout: ${snmpConfig.timeout / 1000} seconds`);
    }

    // Show OIDs if custom model is selected
    if (snmpConfig.upsModel === 'custom' && snmpConfig.customOIDs) {
      logger.logBoxLine('Custom OIDs:');
      logger.logBoxLine(`  Power Status: ${snmpConfig.customOIDs.POWER_STATUS || 'Not set'}`);
      logger.logBoxLine(`  Battery Capacity: ${snmpConfig.customOIDs.BATTERY_CAPACITY || 'Not set'}`);
      logger.logBoxLine(`  Battery Runtime: ${snmpConfig.customOIDs.BATTERY_RUNTIME || 'Not set'}`);
    }
    logger.logBoxLine('Thresholds:');
    logger.logBoxLine(`  Battery: ${thresholds.battery}%`);
    logger.logBoxLine(`  Runtime: ${thresholds.runtime} minutes`);
    
    // Show group assignments if this is a UPS config
    if (config.groups && Array.isArray(config.groups)) {
      logger.logBoxLine(`Group Assignments: ${config.groups.length === 0 ? 'None' : config.groups.join(', ')}`);
    }
    
    logger.logBoxLine(`Check Interval: ${checkInterval / 1000} seconds`);
    logger.logBoxEnd();
  }

  /**
   * Test connection to the UPS
   * @param config Current UPS configuration or legacy config
   */
  private async testConnection(config: any): Promise<void> {
    const upsId = config.id || 'default';
    const upsName = config.name || 'Default UPS';
    logger.log(`\nTesting connection to UPS: ${upsName} (${upsId})...`);
    
    try {
      // Create a test config with a short timeout
      const snmpConfig = config.snmp ? config.snmp : config.snmp;
      const thresholds = config.thresholds ? config.thresholds : config.thresholds;
      
      const testConfig = {
        ...snmpConfig,
        timeout: Math.min(snmpConfig.timeout, 10000), // Use at most 10 seconds for testing
      };

      const status = await this.nupst.getSnmp().getUpsStatus(testConfig);

      const boxWidth = 45;
      logger.logBoxTitle(`Connection Successful: ${upsName}`, boxWidth);
      logger.logBoxLine('UPS Status:');
      logger.logBoxLine(`  Power Status: ${status.powerStatus}`);
      logger.logBoxLine(`  Battery Capacity: ${status.batteryCapacity}%`);
      logger.logBoxLine(`  Runtime Remaining: ${status.batteryRuntime} minutes`);
      logger.logBoxEnd();

      // Check status against thresholds if on battery
      if (status.powerStatus === 'onBattery') {
        this.analyzeThresholds(status, thresholds);
      }
    } catch (error) {
      const errorBoxWidth = 45;
      logger.logBoxTitle(`Connection Failed: ${upsName}`, errorBoxWidth);
      logger.logBoxLine(`Error: ${error.message}`);
      logger.logBoxEnd();
      logger.log("\nPlease check your settings and run 'nupst edit' to reconfigure this UPS.");
    }
  }

  /**
   * Analyze UPS status against thresholds
   * @param status UPS status
   * @param thresholds Threshold configuration
   */
  private analyzeThresholds(status: any, thresholds: any): void {
    const boxWidth = 45;
    logger.logBoxTitle('Threshold Analysis', boxWidth);

    if (status.batteryCapacity < thresholds.battery) {
      logger.logBoxLine('⚠️ WARNING: Battery capacity below threshold');
      logger.logBoxLine(
        `  Current: ${status.batteryCapacity}% | Threshold: ${thresholds.battery}%`
      );
      logger.logBoxLine('  System would initiate shutdown');
    } else {
      logger.logBoxLine('✓ Battery capacity above threshold');
      logger.logBoxLine(
        `  Current: ${status.batteryCapacity}% | Threshold: ${thresholds.battery}%`
      );
    }

    if (status.batteryRuntime < thresholds.runtime) {
      logger.logBoxLine('⚠️ WARNING: Runtime below threshold');
      logger.logBoxLine(
        `  Current: ${status.batteryRuntime} min | Threshold: ${thresholds.runtime} min`
      );
      logger.logBoxLine('  System would initiate shutdown');
    } else {
      logger.logBoxLine('✓ Runtime above threshold');
      logger.logBoxLine(
        `  Current: ${status.batteryRuntime} min | Threshold: ${thresholds.runtime} min`
      );
    }

    logger.logBoxEnd();
  }

  /**
   * Gather SNMP settings
   * @param snmpConfig SNMP configuration object to update
   * @param prompt Function to prompt for user input
   */
  private async gatherSnmpSettings(
    snmpConfig: any,
    prompt: (question: string) => Promise<string>
  ): Promise<void> {
    // SNMP IP Address
    const defaultHost = snmpConfig.host || '127.0.0.1';
    const host = await prompt(`UPS IP Address [${defaultHost}]: `);
    snmpConfig.host = host.trim() || defaultHost;

    // SNMP Port
    const defaultPort = snmpConfig.port || 161;
    const portInput = await prompt(`SNMP Port [${defaultPort}]: `);
    const port = parseInt(portInput, 10);
    snmpConfig.port = portInput.trim() && !isNaN(port) ? port : defaultPort;

    // SNMP Version
    const defaultVersion = snmpConfig.version || 1;
    console.log('\nSNMP Version:');
    console.log('  1) SNMPv1');
    console.log('  2) SNMPv2c');
    console.log('  3) SNMPv3 (with security features)');
    const versionInput = await prompt(`Select SNMP version [${defaultVersion}]: `);
    const version = parseInt(versionInput, 10);
    snmpConfig.version =
      versionInput.trim() && (version === 1 || version === 2 || version === 3)
        ? version
        : defaultVersion;

    if (snmpConfig.version === 1 || snmpConfig.version === 2) {
      // SNMP Community String (for v1/v2c)
      const defaultCommunity = snmpConfig.community || 'public';
      const community = await prompt(`SNMP Community String [${defaultCommunity}]: `);
      snmpConfig.community = community.trim() || defaultCommunity;
    } else if (snmpConfig.version === 3) {
      // SNMP v3 settings
      await this.gatherSnmpV3Settings(snmpConfig, prompt);
    }
  }

  /**
   * Gather SNMPv3 specific settings
   * @param snmpConfig SNMP configuration object to update
   * @param prompt Function to prompt for user input
   */
  private async gatherSnmpV3Settings(
    snmpConfig: any,
    prompt: (question: string) => Promise<string>
  ): Promise<void> {
    console.log('\nSNMPv3 Security Settings:');

    // Security Level
    console.log('\nSecurity Level:');
    console.log('  1) noAuthNoPriv (No Authentication, No Privacy)');
    console.log('  2) authNoPriv (Authentication, No Privacy)');
    console.log('  3) authPriv (Authentication and Privacy)');
    const defaultSecLevel = snmpConfig.securityLevel
      ? snmpConfig.securityLevel === 'noAuthNoPriv'
        ? 1
        : snmpConfig.securityLevel === 'authNoPriv'
        ? 2
        : 3
      : 3;
    const secLevelInput = await prompt(`Select Security Level [${defaultSecLevel}]: `);
    const secLevel = parseInt(secLevelInput, 10) || defaultSecLevel;

    if (secLevel === 1) {
      snmpConfig.securityLevel = 'noAuthNoPriv';
      // No auth, no priv - clear out authentication and privacy settings
      snmpConfig.authProtocol = '';
      snmpConfig.authKey = '';
      snmpConfig.privProtocol = '';
      snmpConfig.privKey = '';
      // Set appropriate timeout for security level
      snmpConfig.timeout = 5000; // 5 seconds for basic security
    } else if (secLevel === 2) {
      snmpConfig.securityLevel = 'authNoPriv';
      // Auth, no priv - clear out privacy settings
      snmpConfig.privProtocol = '';
      snmpConfig.privKey = '';
      // Set appropriate timeout for security level
      snmpConfig.timeout = 10000; // 10 seconds for authentication
    } else {
      snmpConfig.securityLevel = 'authPriv';
      // Set appropriate timeout for security level
      snmpConfig.timeout = 15000; // 15 seconds for full encryption
    }

    // Username
    const defaultUsername = snmpConfig.username || '';
    const username = await prompt(`SNMPv3 Username [${defaultUsername}]: `);
    snmpConfig.username = username.trim() || defaultUsername;

    if (secLevel >= 2) {
      // Authentication settings
      await this.gatherAuthenticationSettings(snmpConfig, prompt);

      if (secLevel === 3) {
        // Privacy settings
        await this.gatherPrivacySettings(snmpConfig, prompt);
      }

      // Allow customizing the timeout value
      const defaultTimeout = snmpConfig.timeout / 1000; // Convert from ms to seconds for display
      console.log(
        '\nSNMPv3 operations with authentication and privacy may require longer timeouts.'
      );
      const timeoutInput = await prompt(`SNMP Timeout in seconds [${defaultTimeout}]: `);
      const timeout = parseInt(timeoutInput, 10);
      if (timeoutInput.trim() && !isNaN(timeout)) {
        snmpConfig.timeout = timeout * 1000; // Convert to ms
      }
    }
  }

  /**
   * Gather authentication settings for SNMPv3
   * @param snmpConfig SNMP configuration object to update
   * @param prompt Function to prompt for user input
   */
  private async gatherAuthenticationSettings(
    snmpConfig: any,
    prompt: (question: string) => Promise<string>
  ): Promise<void> {
    // Authentication protocol
    console.log('\nAuthentication Protocol:');
    console.log('  1) MD5');
    console.log('  2) SHA');
    const defaultAuthProtocol = snmpConfig.authProtocol === 'SHA' ? 2 : 1;
    const authProtocolInput = await prompt(
      `Select Authentication Protocol [${defaultAuthProtocol}]: `
    );
    const authProtocol = parseInt(authProtocolInput, 10) || defaultAuthProtocol;
    snmpConfig.authProtocol = authProtocol === 2 ? 'SHA' : 'MD5';

    // Authentication Key/Password
    const defaultAuthKey = snmpConfig.authKey || '';
    const authKey = await prompt(`Authentication Password ${defaultAuthKey ? '[*****]' : ''}: `);
    snmpConfig.authKey = authKey.trim() || defaultAuthKey;
  }

  /**
   * Gather privacy settings for SNMPv3
   * @param snmpConfig SNMP configuration object to update
   * @param prompt Function to prompt for user input
   */
  private async gatherPrivacySettings(
    snmpConfig: any,
    prompt: (question: string) => Promise<string>
  ): Promise<void> {
    // Privacy protocol
    console.log('\nPrivacy Protocol:');
    console.log('  1) DES');
    console.log('  2) AES');
    const defaultPrivProtocol = snmpConfig.privProtocol === 'AES' ? 2 : 1;
    const privProtocolInput = await prompt(`Select Privacy Protocol [${defaultPrivProtocol}]: `);
    const privProtocol = parseInt(privProtocolInput, 10) || defaultPrivProtocol;
    snmpConfig.privProtocol = privProtocol === 2 ? 'AES' : 'DES';

    // Privacy Key/Password
    const defaultPrivKey = snmpConfig.privKey || '';
    const privKey = await prompt(`Privacy Password ${defaultPrivKey ? '[*****]' : ''}: `);
    snmpConfig.privKey = privKey.trim() || defaultPrivKey;
  }

  /**
   * Gather threshold settings
   * @param thresholds Thresholds configuration object to update
   * @param prompt Function to prompt for user input
   */
  private async gatherThresholdSettings(
    thresholds: any,
    prompt: (question: string) => Promise<string>
  ): Promise<void> {
    console.log('\nShutdown Thresholds:');

    // Battery threshold
    const defaultBatteryThreshold = thresholds.battery || 60;
    const batteryThresholdInput = await prompt(
      `Battery percentage threshold [${defaultBatteryThreshold}%]: `
    );
    const batteryThreshold = parseInt(batteryThresholdInput, 10);
    thresholds.battery =
      batteryThresholdInput.trim() && !isNaN(batteryThreshold)
        ? batteryThreshold
        : defaultBatteryThreshold;

    // Runtime threshold
    const defaultRuntimeThreshold = thresholds.runtime || 20;
    const runtimeThresholdInput = await prompt(
      `Runtime minutes threshold [${defaultRuntimeThreshold} minutes]: `
    );
    const runtimeThreshold = parseInt(runtimeThresholdInput, 10);
    thresholds.runtime =
      runtimeThresholdInput.trim() && !isNaN(runtimeThreshold)
        ? runtimeThreshold
        : defaultRuntimeThreshold;
  }

  /**
   * Gather UPS model settings
   * @param snmpConfig SNMP configuration object to update
   * @param prompt Function to prompt for user input
   */
  private async gatherUpsModelSettings(
    snmpConfig: any,
    prompt: (question: string) => Promise<string>
  ): Promise<void> {
    console.log('\nUPS Model Selection:');
    console.log('  1) CyberPower');
    console.log('  2) APC');
    console.log('  3) Eaton');
    console.log('  4) TrippLite');
    console.log('  5) Liebert/Vertiv');
    console.log('  6) Custom (Advanced)');

    const defaultModelValue =
      snmpConfig.upsModel === 'cyberpower'
        ? 1
        : snmpConfig.upsModel === 'apc'
        ? 2
        : snmpConfig.upsModel === 'eaton'
        ? 3
        : snmpConfig.upsModel === 'tripplite'
        ? 4
        : snmpConfig.upsModel === 'liebert'
        ? 5
        : snmpConfig.upsModel === 'custom'
        ? 6
        : 1;

    const modelInput = await prompt(`Select UPS model [${defaultModelValue}]: `);
    const modelValue = parseInt(modelInput, 10) || defaultModelValue;

    if (modelValue === 1) {
      snmpConfig.upsModel = 'cyberpower';
    } else if (modelValue === 2) {
      snmpConfig.upsModel = 'apc';
    } else if (modelValue === 3) {
      snmpConfig.upsModel = 'eaton';
    } else if (modelValue === 4) {
      snmpConfig.upsModel = 'tripplite';
    } else if (modelValue === 5) {
      snmpConfig.upsModel = 'liebert';
    } else if (modelValue === 6) {
      snmpConfig.upsModel = 'custom';
      console.log('\nEnter custom OIDs for your UPS:');
      console.log('(Leave blank to use standard RFC 1628 OIDs as fallback)');

      // Custom OIDs
      const powerStatusOID = await prompt('Power Status OID: ');
      const batteryCapacityOID = await prompt('Battery Capacity OID: ');
      const batteryRuntimeOID = await prompt('Battery Runtime OID: ');

      // Create custom OIDs object
      snmpConfig.customOIDs = {
        POWER_STATUS: powerStatusOID.trim(),
        BATTERY_CAPACITY: batteryCapacityOID.trim(),
        BATTERY_RUNTIME: batteryRuntimeOID.trim(),
      };
    }
  }

  /**
   * Display UPS configuration summary
   * @param ups UPS configuration
   */
  private displayUpsConfigSummary(ups: any): void {
    const boxWidth = 45;
    logger.log('');
    logger.logBoxTitle(`UPS Configuration: ${ups.name}`, boxWidth);
    logger.logBoxLine(`UPS ID: ${ups.id}`);
    logger.logBoxLine(`SNMP Host: ${ups.snmp.host}:${ups.snmp.port}`);
    logger.logBoxLine(`SNMP Version: ${ups.snmp.version}`);
    logger.logBoxLine(`UPS Model: ${ups.snmp.upsModel}`);
    logger.logBoxLine(
      `Thresholds: ${ups.thresholds.battery}% battery, ${ups.thresholds.runtime} min runtime`
    );
    if (ups.groups && ups.groups.length > 0) {
      logger.logBoxLine(`Groups: ${ups.groups.join(', ')}`);
    } else {
      logger.logBoxLine('Groups: None');
    }
    logger.logBoxEnd();
    logger.log('');
  }

  /**
   * Optionally test connection to UPS
   * @param snmpConfig SNMP configuration to test
   * @param prompt Function to prompt for user input
   */
  private async optionallyTestConnection(
    snmpConfig: any,
    prompt: (question: string) => Promise<string>
  ): Promise<void> {
    const testConnection = await prompt(
      'Would you like to test the connection to your UPS? (y/N): '
    );
    if (testConnection.toLowerCase() === 'y') {
      logger.log('\nTesting connection to UPS...');
      try {
        // Create a test config with a short timeout
        const testConfig = {
          ...snmpConfig,
          timeout: Math.min(snmpConfig.timeout, 10000), // Use at most 10 seconds for testing
        };

        const status = await this.nupst.getSnmp().getUpsStatus(testConfig);
        const boxWidth = 45;
        logger.log('');
        logger.logBoxTitle('Connection Successful!', boxWidth);
        logger.logBoxLine('UPS Status:');
        logger.logBoxLine(`✓ Power Status: ${status.powerStatus}`);
        logger.logBoxLine(`✓ Battery Capacity: ${status.batteryCapacity}%`);
        logger.logBoxLine(`✓ Runtime Remaining: ${status.batteryRuntime} minutes`);
        logger.logBoxEnd();
      } catch (error) {
        const errorBoxWidth = 45;
        logger.log('');
        logger.logBoxTitle('Connection Failed!', errorBoxWidth);
        logger.logBoxLine(`Error: ${error.message}`);
        logger.logBoxEnd();
        logger.log('\nPlease check your settings and try again.');
      }
    }
  }

  /**
   * Check if the systemd service is running and restart it if it is
   * This is useful after configuration changes
   */
  public async restartServiceIfRunning(): Promise<void> {
    try {
      // Check if the service is active
      const isActive =
        execSync('systemctl is-active nupst.service || true').toString().trim() === 'active';

      if (isActive) {
        // Service is running, restart it
        const boxWidth = 45;
        logger.logBoxTitle('Service Update', boxWidth);
        logger.logBoxLine('Configuration has changed.');
        logger.logBoxLine('Restarting NUPST service to apply changes...');

        try {
          if (process.getuid && process.getuid() === 0) {
            // We have root access, restart directly
            execSync('systemctl restart nupst.service');
            logger.logBoxLine('Service restarted successfully.');
          } else {
            // No root access, show instructions
            logger.logBoxLine('Please restart the service with:');
            logger.logBoxLine('  sudo systemctl restart nupst.service');
          }
        } catch (error) {
          logger.logBoxLine(`Error restarting service: ${error.message}`);
          logger.logBoxLine('You may need to restart the service manually:');
          logger.logBoxLine('  sudo systemctl restart nupst.service');
        }

        logger.logBoxEnd();
      }
    } catch (error) {
      // Ignore errors checking service status
    }
  }
}