const express = require('express');
const http = require('http');
const https = require('https');
const cors = require('cors');
const fs = require('fs');
const os = require('os');
const path = require('path');
const { exec } = require('child_process');
const cron = require('node-cron');

const app = express();

// Configurar middleware para habilitar CORS
app.use(cors());

// Ruta de proxy
app.all('/proxy', (req, res) => {
  const url = req.query.url;

  if (!url) {
    return res.status(400).send('La URL de destino no está especificada.');
  }

  const protocol = url.startsWith('https') ? https : http;
  protocol.get(url, (proxyRes) => {
    res.set(proxyRes.headers);
    res.set('Access-Control-Allow-Origin', '*');

    proxyRes.on('data', (chunk) => {
      res.write(chunk);
    });

    proxyRes.on('end', () => {
      res.end();
    });
  }).on('error', (err) => {
    console.error('Error al hacer la solicitud:', err.message);
    res.status(500).send('Error al realizar la solicitud al servidor de destino.');
  });
});

const httpsOptions = {
  key: fs.readFileSync('cert/key.pem'),
  cert: fs.readFileSync('cert/cert.crt'),
  passphrase: "changeit"
};

const PORT = process.env.PORT || 2227;
https.createServer(httpsOptions, app).listen(PORT, () => {
  console.log(`Proxy funcionando en el puerto ${PORT}`);
});

function getDiskUsage(drive, callback) {
  const command = `powershell -command "Get-PSDrive -PSProvider FileSystem | Where-Object { $_.Name -eq '${drive[0]}' } | Select-Object Used,Free, @{Name='Total';Expression={$_.Used + $_.Free}}"`;

  exec(command, (error, stdout, stderr) => {
    if (error) {
      console.error(`Error getting disk usage for ${drive}:`, error);
      callback(error, null);
      return;
    }

    const lines = stdout.trim().split('\n');
    const data = lines[2].trim().split(/\s+/);

    const used = parseInt(data[0]);
    const free = parseInt(data[1]);
    const total = used + free;

    const diskUsage = {
      total: (total / (1024 ** 3)).toFixed(2) + ' GB',
      free: (free / (1024 ** 3)).toFixed(2) + ' GB',
      used: (used / (1024 ** 3)).toFixed(2) + ' GB',
      usedPercentage: ((used / total) * 100).toFixed(2) + ' %',
      freePercentage: ((free / total) * 100).toFixed(2) + ' %'
    };

    callback(null, diskUsage);
  });
}

function logMemoryUsage() {
    const totalMem = os.totalmem();
    const freeMem = os.freemem();
    const usedMem = totalMem - freeMem;

    const memoryUsage = {
        total: (totalMem / (1024 ** 3)).toFixed(2) + ' GB',
        used: (usedMem / (1024 ** 3)).toFixed(2) + ' GB',
        free: (freeMem / (1024 ** 3)).toFixed(2) + ' GB',
        usedPercentage: ((usedMem / totalMem) * 100).toFixed(2) + ' %',
        freePercentage: ((freeMem / totalMem) * 100).toFixed(2) + ' %'
    };

    const logData = {
      timestamp: new Date().toISOString(),
      memoryUsage
    };
  
    const logFilePath = path.join('F:/ms4w/Apache/htdocs/summary_system', 'memory_usage_log.json');
  
    fs.writeFile(logFilePath, JSON.stringify(logData, null, 2), function(err) {
      if (err) {
        console.error('Error writing memory usage log file:', err);
      } 
    });
}

function logDiskUsage() {
  getDiskUsage('C:', (error, diskUsageC) => {
    if (error) {
      return;
    }
    getDiskUsage('F:', (error, diskUsageF) => {
      if (error) {
        return;
      }

      const diskUsage = { C: diskUsageC, F: diskUsageF };

      const logData = {
        timestamp: new Date().toISOString(),
        diskUsage
      };

      const logFilePath = path.join('F:/ms4w/Apache/htdocs/summary_system', 'disk_usage_log.json');

      fs.writeFile(logFilePath, JSON.stringify(logData, null, 2), function(err) {
        if (err) {
          console.error('Error writing disk usage log file:', err);
        } 
      });
    });
  });
}

function getCpuUsage() {
  const cpus = os.cpus();
  const THRESHOLD = 1.0; // Porcentaje mínimo para considerar un núcleo

  return new Promise((resolve) => {
    const initialTimes = cpus.map(cpu => cpu.times);

    setTimeout(() => {
      const finalTimes = os.cpus().map(cpu => cpu.times);

      const usagePercentages = cpus.map((cpu, i) => {
        const initial = initialTimes[i];
        const final = finalTimes[i];
        
        const totalInitial = Object.values(initial).reduce((acc, value) => acc + value, 0);
        const totalFinal = Object.values(final).reduce((acc, value) => acc + value, 0);

        const totalDiff = totalFinal - totalInitial;
        const usageDiff = (final.user - initial.user) + (final.sys - initial.sys);

        const percentage = (usageDiff / totalDiff) * 100;
        return percentage >= THRESHOLD ? percentage : 0;
      });

      const totalUsage = usagePercentages.reduce((acc, usage) => acc + usage, 0);
      const validCount = usagePercentages.filter(usage => usage > 0).length;
      const averageUsage = validCount > 0 ? totalUsage / validCount : 0;

      resolve(averageUsage);
    }, 1000); // Espera 1 segundo
  });
}

function logCpuUsage() {
  getCpuUsage().then(totalUsage => {
    const logData = {
      timestamp: new Date().toISOString(),
      totalUsage: totalUsage.toFixed(2) + '%'
    };

    const logFilePath = path.join('F:/ms4w/Apache/htdocs/summary_system', 'cpu_usage_log.json');

    fs.writeFile(logFilePath, JSON.stringify(logData, null, 2), function(err) {
      if (err) {
        console.error('Error writing CPU usage log file:', err);
      }
    });
  });
}

// Ejecuta cada 60 segundos
setInterval(() => {
  logMemoryUsage();
  logDiskUsage();
  logCpuUsage();
}, 60000);

// Comando para reiniciar el servidor
const command = 'shutdown /r /f /t 0';

// Programar la tarea para que se ejecute todos los días a las 11:59 PM
cron.schedule('21 14 * * *', () => {
  exec(command, (error, stdout, stderr) => {

    console.info("Ejecutar Cron...");

      if (error) {
          console.error(`Error al intentar reiniciar el servidor: ${error.message}`);
          return;
      }
      if (stderr) {
          console.error(`stderr: ${stderr}`);
          return;
      }
      console.log(`Servidor reiniciado: ${stdout}`);
  });
});