/**
 * Health Monitor for MCP SSH Manager
 * Provides system health checks, service monitoring, and process management
 */

import { logger } from './logger.js';

// Health status levels
export const HEALTH_STATUS = {
  HEALTHY: 'healthy',
  WARNING: 'warning',
  CRITICAL: 'critical',
  UNKNOWN: 'unknown'
};

// Common services to monitor
export const COMMON_SERVICES = {
  nginx: { systemd: 'nginx', sysv: 'nginx' },
  apache: { systemd: 'apache2', sysv: 'apache2' },
  mysql: { systemd: 'mysql', sysv: 'mysql' },
  postgresql: { systemd: 'postgresql', sysv: 'postgresql' },
  mongodb: { systemd: 'mongod', sysv: 'mongod' },
  redis: { systemd: 'redis', sysv: 'redis-server' },
  docker: { systemd: 'docker', sysv: 'docker' },
  ssh: { systemd: 'sshd', sysv: 'ssh' }
};

/**
 * Build command to check CPU usage
 */
export function buildCPUCheckCommand() {
  // Get CPU usage using top, show idle percentage, calculate used
  return 'top -bn1 | grep "Cpu(s)" | sed "s/.*, *\\([0-9.]*\\)%* id.*/\\1/" | awk \'{print 100 - $1}\'';
}

/**
 * Build command to check memory usage
 */
export function buildMemoryCheckCommand() {
  // Returns: total, used, free, available in MB and percentage
  return 'free -m | awk \'NR==2{printf "{\\"total\\":%s,\\"used\\":%s,\\"free\\":%s,\\"percent\\":%.2f}", $2,$3,$4,$3*100/$2}\'';
}

/**
 * Build command to check disk usage
 */
export function buildDiskCheckCommand(mountPoint = '/') {
  // Returns JSON with disk usage for specific mount point or all
  if (mountPoint === 'all') {
    return 'df -h | awk \'NR>1 {gsub(/%/,"",$5); printf "{\\"mount\\":\\"%s\\",\\"size\\":\\"%s\\",\\"used\\":\\"%s\\",\\"avail\\":\\"%s\\",\\"percent\\":%s}\\n", $6,$2,$3,$4,$5}\'';
  }
  return `df -h "${mountPoint}" | awk 'NR>1 {gsub(/%/,"",$5); printf "{\\"mount\\":\\"%s\\",\\"size\\":\\"%s\\",\\"used\\":\\"%s\\",\\"avail\\":\\"%s\\",\\"percent\\":%s}", $6,$2,$3,$4,$5}'`;
}

/**
 * Build command to check network statistics
 */
export function buildNetworkCheckCommand() {
  // Get basic network stats (RX/TX bytes)
  return 'cat /proc/net/dev | awk \'NR>2 {printf "{\\"interface\\":\\"%s\\",\\"rx_bytes\\":%s,\\"tx_bytes\\":%s}\\n", $1,$2,$10}\' | grep -v "lo:"';
}

/**
 * Build command to check load average
 */
export function buildLoadAverageCommand() {
  return 'uptime | awk -F\'load average:\' \'{print $2}\' | sed \'s/^[ \\t]*//\'';
}

/**
 * Build command to check system uptime
 */
export function buildUptimeCommand() {
  return 'uptime -p 2>/dev/null || uptime | awk \'{print $3,$4}\' | sed \'s/,//\'';
}

/**
 * Parse CPU usage output
 */
export function parseCPUUsage(output) {
  const usage = parseFloat(output.trim());
  return {
    usage: usage.toFixed(2),
    percent: usage,
    status: usage > 90 ? HEALTH_STATUS.CRITICAL : usage > 70 ? HEALTH_STATUS.WARNING : HEALTH_STATUS.HEALTHY
  };
}

/**
 * Parse memory usage output
 */
export function parseMemoryUsage(output) {
  try {
    const mem = JSON.parse(output.trim());
    return {
      total_mb: mem.total,
      used_mb: mem.used,
      free_mb: mem.free,
      percent: parseFloat(mem.percent),
      status: mem.percent > 90 ? HEALTH_STATUS.CRITICAL : mem.percent > 80 ? HEALTH_STATUS.WARNING : HEALTH_STATUS.HEALTHY
    };
  } catch (error) {
    logger.warn('Failed to parse memory output', { error: error.message });
    return { status: HEALTH_STATUS.UNKNOWN };
  }
}

/**
 * Parse disk usage output
 */
export function parseDiskUsage(output) {
  const lines = output.trim().split('\n').filter(l => l);
  const disks = [];

  for (const line of lines) {
    try {
      const disk = JSON.parse(line);
      disk.status = disk.percent > 90 ? HEALTH_STATUS.CRITICAL : disk.percent > 80 ? HEALTH_STATUS.WARNING : HEALTH_STATUS.HEALTHY;
      disks.push(disk);
    } catch (error) {
      logger.warn('Failed to parse disk line', { line, error: error.message });
    }
  }

  return disks;
}

/**
 * Parse network statistics
 */
export function parseNetworkStats(output) {
  const lines = output.trim().split('\n').filter(l => l);
  const interfaces = [];

  for (const line of lines) {
    try {
      const iface = JSON.parse(line);
      // Convert bytes to MB
      iface.rx_mb = (iface.rx_bytes / 1024 / 1024).toFixed(2);
      iface.tx_mb = (iface.tx_bytes / 1024 / 1024).toFixed(2);
      interfaces.push(iface);
    } catch (error) {
      logger.warn('Failed to parse network line', { line, error: error.message });
    }
  }

  return interfaces;
}

/**
 * Determine overall health status
 */
export function determineOverallHealth(cpu, memory, disks) {
  const statuses = [cpu.status, memory.status, ...disks.map(d => d.status)];

  if (statuses.includes(HEALTH_STATUS.CRITICAL)) {
    return HEALTH_STATUS.CRITICAL;
  }
  if (statuses.includes(HEALTH_STATUS.WARNING)) {
    return HEALTH_STATUS.WARNING;
  }
  if (statuses.includes(HEALTH_STATUS.UNKNOWN)) {
    return HEALTH_STATUS.UNKNOWN;
  }
  return HEALTH_STATUS.HEALTHY;
}

/**
 * Build command to check service status (systemd or sysv)
 */
export function buildServiceStatusCommand(serviceName) {
  // Try systemd first, fallback to sysv
  return `
    if command -v systemctl >/dev/null 2>&1; then
      systemctl is-active ${serviceName} 2>/dev/null >/dev/null && echo "ACTIVE" || echo "INACTIVE"
      systemctl is-enabled ${serviceName} 2>/dev/null >/dev/null && echo "ENABLED" || echo "DISABLED"
      systemctl status ${serviceName} 2>/dev/null | grep "Main PID" | awk '{print $3}' | cut -d'(' -f1
      systemctl status ${serviceName} 2>/dev/null | grep "Active:" | sed 's/.*Active: //' | awk '{print $1,$2,$3}'
    elif command -v service >/dev/null 2>&1; then
      service ${serviceName} status >/dev/null 2>&1 && echo "ACTIVE" || echo "INACTIVE"
      echo "UNKNOWN"
      pgrep -f ${serviceName} | head -1 || echo ""
      echo "sysv"
    else
      echo "UNKNOWN"
      echo "UNKNOWN"
      echo ""
      echo "no-init-system"
    fi
  `.trim();
}

/**
 * Parse service status output
 */
export function parseServiceStatus(output, serviceName) {
  const lines = output.trim().split('\n');
  const [status, enabled, pid, details] = lines;

  return {
    name: serviceName,
    status: status === 'ACTIVE' ? 'running' : 'stopped',
    enabled: enabled === 'ENABLED' ? 'yes' : enabled === 'DISABLED' ? 'no' : 'unknown',
    pid: pid && pid !== '' ? parseInt(pid) : null,
    details: details || 'unknown',
    health: status === 'ACTIVE' ? HEALTH_STATUS.HEALTHY : HEALTH_STATUS.CRITICAL
  };
}

/**
 * Build command to list running processes
 */
export function buildProcessListCommand(options = {}) {
  const {
    sortBy = 'cpu',  // cpu, memory, pid
    limit = 20,
    filter = null
  } = options;

  let sortFlag = sortBy === 'memory' ? '-m' : '-c';  // -c for CPU, -m for memory
  let command = `ps aux --sort=${sortFlag === '-c' ? '-pcpu' : '-pmem'} | head -n ${limit + 1}`;

  if (filter) {
    command += ` | grep -i "${filter}"`;
  }

  // Format output as JSON-like structure
  command += ' | awk \'NR>1 {printf "{\\"user\\":\\"%s\\",\\"pid\\":%s,\\"cpu\\":%.1f,\\"mem\\":%.1f,\\"vsz\\":%s,\\"rss\\":%s,\\"stat\\":\\"%s\\",\\"start\\":\\"%s\\",\\"time\\":\\"%s\\",\\"command\\":\\"%s\\"}\\n", $1,$2,$3,$4,$5,$6,$8,$9,$10,substr($0,index($0,$11))}\'';

  return command;
}

/**
 * Parse process list output
 */
export function parseProcessList(output) {
  const lines = output.trim().split('\n').filter(l => l);
  const processes = [];

  for (const line of lines) {
    try {
      const proc = JSON.parse(line);
      processes.push(proc);
    } catch (error) {
      logger.warn('Failed to parse process line', { line, error: error.message });
    }
  }

  return processes;
}

/**
 * Build command to kill a process
 */
export function buildKillProcessCommand(pid, signal = 'TERM') {
  // Validate PID is numeric
  if (!Number.isInteger(pid) || pid <= 0) {
    throw new Error(`Invalid PID: ${pid}`);
  }

  const validSignals = ['TERM', 'KILL', 'HUP', 'INT', 'QUIT'];
  if (!validSignals.includes(signal)) {
    throw new Error(`Invalid signal: ${signal}. Valid signals: ${validSignals.join(', ')}`);
  }

  return `kill -${signal} ${pid}`;
}

/**
 * Build command to get process info
 */
export function buildProcessInfoCommand(pid) {
  return `ps -p ${pid} -o user,pid,pcpu,pmem,vsz,rss,stat,start,time,cmd --no-headers | awk '{printf "{\\"user\\":\\"%s\\",\\"pid\\":%s,\\"cpu\\":%.1f,\\"mem\\":%.1f,\\"vsz\\":%s,\\"rss\\":%s,\\"stat\\":\\"%s\\",\\"start\\":\\"%s\\",\\"time\\":\\"%s\\",\\"command\\":\\"%s\\"}", $1,$2,$3,$4,$5,$6,$7,$8,$9,substr($0,index($0,$10))}'`;
}

/**
 * Create alert configuration
 */
export function createAlertConfig(thresholds) {
  const defaults = {
    cpu: 80,
    memory: 90,
    disk: 85,
    enabled: true
  };

  return {
    ...defaults,
    ...thresholds,
    created_at: new Date().toISOString()
  };
}

/**
 * Build command to save alert config
 */
export function buildSaveAlertConfigCommand(config, configPath = '/etc/ssh-manager-alerts.json') {
  const jsonData = JSON.stringify(config, null, 2);
  const escapedJson = jsonData.replace(/'/g, '\'\\\'\'');
  return `echo '${escapedJson}' > "${configPath}"`;
}

/**
 * Build command to load alert config
 */
export function buildLoadAlertConfigCommand(configPath = '/etc/ssh-manager-alerts.json') {
  return `cat "${configPath}" 2>/dev/null || echo '{}'`;
}

/**
 * Check if thresholds are exceeded
 */
export function checkAlertThresholds(metrics, thresholds) {
  const alerts = [];

  if (thresholds.cpu && metrics.cpu && metrics.cpu.percent > thresholds.cpu) {
    alerts.push({
      type: 'cpu',
      severity: 'warning',
      message: `CPU usage (${metrics.cpu.percent}%) exceeds threshold (${thresholds.cpu}%)`,
      value: metrics.cpu.percent,
      threshold: thresholds.cpu
    });
  }

  if (thresholds.memory && metrics.memory && metrics.memory.percent > thresholds.memory) {
    alerts.push({
      type: 'memory',
      severity: 'warning',
      message: `Memory usage (${metrics.memory.percent}%) exceeds threshold (${thresholds.memory}%)`,
      value: metrics.memory.percent,
      threshold: thresholds.memory
    });
  }

  if (thresholds.disk && metrics.disks) {
    for (const disk of metrics.disks) {
      if (disk.percent > thresholds.disk) {
        alerts.push({
          type: 'disk',
          severity: 'warning',
          message: `Disk usage on ${disk.mount} (${disk.percent}%) exceeds threshold (${thresholds.disk}%)`,
          mount: disk.mount,
          value: disk.percent,
          threshold: thresholds.disk
        });
      }
    }
  }

  return alerts;
}

/**
 * Build comprehensive health check command
 */
export function buildComprehensiveHealthCheckCommand() {
  return `
    echo "=== CPU ==="
    ${buildCPUCheckCommand()}
    echo "=== MEMORY ==="
    ${buildMemoryCheckCommand()}
    echo "=== DISK ==="
    ${buildDiskCheckCommand('all')}
    echo "=== LOAD ==="
    ${buildLoadAverageCommand()}
    echo "=== UPTIME ==="
    ${buildUptimeCommand()}
    echo "=== NETWORK ==="
    ${buildNetworkCheckCommand()}
  `.trim();
}

/**
 * Parse comprehensive health check output
 */
export function parseComprehensiveHealthCheck(output) {
  const sections = output.split('=== ').filter(s => s);
  const result = {};

  for (const section of sections) {
    const [name, ...content] = section.split('\n');
    const data = content.join('\n').trim();

    switch (name.toLowerCase().trim()) {
    case 'cpu ===':
      result.cpu = parseCPUUsage(data);
      break;
    case 'memory ===':
      result.memory = parseMemoryUsage(data);
      break;
    case 'disk ===':
      result.disks = parseDiskUsage(data);
      break;
    case 'load ===':
      result.load_average = data;
      break;
    case 'uptime ===':
      result.uptime = data;
      break;
    case 'network ===':
      result.network = parseNetworkStats(data);
      break;
    }
  }

  // Determine overall health
  if (result.cpu && result.memory && result.disks) {
    result.overall_status = determineOverallHealth(result.cpu, result.memory, result.disks);
  }

  return result;
}

/**
 * Get common service names for detection
 */
export function getCommonServices() {
  return Object.keys(COMMON_SERVICES);
}

/**
 * Resolve service name (handle both systemd and sysv names)
 */
export function resolveServiceName(shortName) {
  const service = COMMON_SERVICES[shortName.toLowerCase()];
  return service ? service.systemd : shortName;
}
