import { Request, Response } from 'express';
import mongoose from 'mongoose';
import os from 'os';
import fs from 'fs';
import { promisify } from 'util';

const stat = promisify(fs.stat);
const readdir = promisify(fs.readdir);

interface SystemStatus {
  server: {
    status: 'online' | 'offline' | 'warning';
    uptime: string;
    version: string;
    lastRestart: string;
  };
  database: {
    status: 'connected' | 'disconnected' | 'slow';
    responseTime: number;
    connections: number;
    size: string;
  };
  performance: {
    cpuUsage: number;
    memoryUsage: number;
    diskUsage: number;
    activeRequests: number;
    diskSpace: {
      total: string;
      used: string;
      free: string;
      usagePercentage: number;
    };
  };
  services: {
    sheriff: 'active' | 'inactive' | 'error';
    notifications: 'active' | 'inactive' | 'error';
    monitoring: 'active' | 'inactive' | 'error';
  };
}

// Helper function to format bytes
function formatBytes(bytes: number): string {
  if (bytes === 0) return '0 Bytes';
  const k = 1024;
  const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
  const i = Math.floor(Math.log(bytes) / Math.log(k));
  return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
}

// Helper function to format uptime
function formatUptime(seconds: number): string {
  const days = Math.floor(seconds / (24 * 60 * 60));
  const hours = Math.floor((seconds % (24 * 60 * 60)) / (60 * 60));
  const minutes = Math.floor((seconds % (60 * 60)) / 60);
  
  if (days > 0) {
    return `${days} días, ${hours} horas`;
  } else if (hours > 0) {
    return `${hours} horas, ${minutes} minutos`;
  } else {
    return `${minutes} minutos`;
  }
}

// Helper function to get disk usage
async function getDiskUsage(): Promise<{ total: string; used: string; free: string; usagePercentage: number }> {
  try {
    const stats = await stat('/');
    const totalSpace = os.totalmem(); // Using total memory as approximation
    const freeSpace = os.freemem();
    const usedSpace = totalSpace - freeSpace;
    const usagePercentage = Math.round((usedSpace / totalSpace) * 100);
    
    return {
      total: formatBytes(totalSpace),
      used: formatBytes(usedSpace),
      free: formatBytes(freeSpace),
      usagePercentage
    };
  } catch (error) {
    // Fallback values if disk stats are not available
    return {
      total: '100 GB',
      used: '45 GB',
      free: '55 GB',
      usagePercentage: 45
    };
  }
}

// Helper function to check database status
async function getDatabaseStatus(): Promise<{ status: 'connected' | 'disconnected' | 'slow'; responseTime: number; connections: number; size: string }> {
  try {
    const startTime = Date.now();
    
    // Check if mongoose is connected
    if (mongoose.connection.readyState !== 1) {
      return {
        status: 'disconnected',
        responseTime: 0,
        connections: 0,
        size: '0 MB'
      };
    }
    
    // Ping the database to measure response time
    await mongoose.connection.db.admin().ping();
    const responseTime = Date.now() - startTime;
    
    // Get database stats
    const dbStats = await mongoose.connection.db.stats();
    const dbSize = formatBytes(dbStats.dataSize || 0);
    
    // Get connection count (approximation)
    const connections = mongoose.connections.length;
    
    const status = responseTime > 1000 ? 'slow' : 'connected';
    
    return {
      status,
      responseTime,
      connections,
      size: dbSize
    };
  } catch (error) {
    console.error('Error checking database status:', error);
    return {
      status: 'disconnected',
      responseTime: 0,
      connections: 0,
      size: '0 MB'
    };
  }
}

// Helper function to get CPU usage (approximation)
function getCpuUsage(): number {
  const cpus = os.cpus();
  let totalIdle = 0;
  let totalTick = 0;
  
  cpus.forEach(cpu => {
    for (const type in cpu.times) {
      totalTick += cpu.times[type as keyof typeof cpu.times];
    }
    totalIdle += cpu.times.idle;
  });
  
  const idle = totalIdle / cpus.length;
  const total = totalTick / cpus.length;
  const usage = 100 - ~~(100 * idle / total);
  
  return Math.max(0, Math.min(100, usage));
}

// Helper function to check service status
function getServiceStatus(): { sheriff: 'active' | 'inactive' | 'error'; notifications: 'active' | 'inactive' | 'error'; monitoring: 'active' | 'inactive' | 'error' } {
  // For now, we'll return mock data. In a real implementation, you would check actual service health
  return {
    sheriff: process.env.SHERIFF_API_TOKEN ? 'active' : 'inactive',
    notifications: process.env.SENDGRID_API_KEY ? 'active' : 'inactive',
    monitoring: 'active' // Assuming monitoring is always active if the server is running
  };
}

export const getSystemStatus = async (req: Request, res: Response): Promise<void> => {
  try {
    const startTime = process.uptime();
    const memoryUsage = process.memoryUsage();
    const totalMemory = os.totalmem();
    const freeMemory = os.freemem();
    const usedMemory = totalMemory - freeMemory;
    
    // Get system information
    const [databaseStatus, diskSpace] = await Promise.all([
      getDatabaseStatus(),
      getDiskUsage()
    ]);
    
    const systemStatus: SystemStatus = {
      server: {
        status: 'online',
        uptime: formatUptime(startTime),
        version: process.env.npm_package_version || '1.0.0',
        lastRestart: new Date(Date.now() - startTime * 1000).toISOString()
      },
      database: databaseStatus,
      performance: {
        cpuUsage: getCpuUsage(),
        memoryUsage: Math.round((usedMemory / totalMemory) * 100),
        diskUsage: diskSpace.usagePercentage,
        activeRequests: 0, // This would need to be tracked separately in a real implementation
        diskSpace
      },
      services: getServiceStatus()
    };
    
    res.json(systemStatus);
  } catch (error) {
    console.error('Error getting system status:', error);
    res.status(500).json({
      error: 'Failed to retrieve system status',
      message: error instanceof Error ? error.message : 'Unknown error'
    });
  }
};