/**
 * ═══════════════════════════════════════════════════════════════════════════════
 * LOOPUMAN HEALTH MONITORING & ALERTING
 * ═══════════════════════════════════════════════════════════════════════════════
 * 
 * Monitors platform health and alerts Ray of issues.
 * 
 * MONITORS:
 * - Server uptime
 * - Database connectivity
 * - Celo blockchain connection
 * - Stripe webhook health
 * - Bot responsiveness
 * - Error rates
 * - Performance metrics
 * 
 * ALERTS VIA:
 * - Telegram Admin Bot
 * - Email (optional)
 * 
 * ═══════════════════════════════════════════════════════════════════════════════
 */

'use strict';

const { createClient } = require('@supabase/supabase-js');
const { ethers } = require('ethers');
const os = require('os');

const supabase = createClient(process.env.SUPABASE_URL, process.env.SUPABASE_SERVICE_KEY);

// Admin notification config
const ADMIN_TELEGRAM_ID = process.env.ADMIN_TELEGRAM_ID;
let adminBot = null;

// Health check state
const healthState = {
  lastCheck: null,
  status: 'unknown',
  services: {},
  alerts: []
};

// ═══════════════════════════════════════════════════════════════════════════════
// CONFIGURATION
// ═══════════════════════════════════════════════════════════════════════════════

const CONFIG = {
  // Check intervals
  CHECK_INTERVAL_MS: 60 * 1000, // Every minute
  
  // Thresholds
  thresholds: {
    cpu_warning: 80,           // CPU > 80%
    cpu_critical: 95,          // CPU > 95%
    memory_warning: 80,        // Memory > 80%
    memory_critical: 95,       // Memory > 95%
    error_rate_warning: 0.05,  // > 5% error rate
    error_rate_critical: 0.15, // > 15% error rate
    response_time_warning: 2000, // > 2s
    response_time_critical: 5000, // > 5s
    webhook_delay_warning: 300,   // > 5 min since last webhook
    webhook_delay_critical: 900   // > 15 min since last webhook
  },
  
  // Alert cooldown (don't spam same alert)
  ALERT_COOLDOWN_MS: 15 * 60 * 1000 // 15 minutes
};

// ═══════════════════════════════════════════════════════════════════════════════
// SERVICE HEALTH CHECKS
// ═══════════════════════════════════════════════════════════════════════════════

/**
 * Check database connectivity
 */
async function checkDatabase() {
  const start = Date.now();
  try {
    const { data, error } = await supabase
      .from('app_users')
      .select('id')
      .limit(1);
    
    const responseTime = Date.now() - start;
    
    if (error) throw error;
    
    return {
      status: responseTime < CONFIG.thresholds.response_time_warning ? 'healthy' : 'degraded',
      responseTime,
      message: `Connected (${responseTime}ms)`
    };
  } catch (error) {
    return {
      status: 'unhealthy',
      responseTime: Date.now() - start,
      message: error.message
    };
  }
}

/**
 * Check Celo blockchain connectivity
 */
async function checkCelo() {
  const start = Date.now();
  try {
    const provider = new ethers.JsonRpcProvider(process.env.CELO_RPC_URL || 'https://forno.celo.org');
    const blockNumber = await provider.getBlockNumber();
    const responseTime = Date.now() - start;
    
    return {
      status: 'healthy',
      responseTime,
      blockNumber,
      message: `Block #${blockNumber} (${responseTime}ms)`
    };
  } catch (error) {
    return {
      status: 'unhealthy',
      responseTime: Date.now() - start,
      message: error.message
    };
  }
}

/**
 * Check Stripe webhook health
 */
async function checkStripeWebhook() {
  try {
    // Get last successful webhook
    const { data } = await supabase
      .from('stripe_transactions')
      .select('completed_at')
      .eq('status', 'completed')
      .order('completed_at', { ascending: false })
      .limit(1);
    
    if (!data || data.length === 0) {
      return {
        status: 'unknown',
        message: 'No transactions yet'
      };
    }
    
    const lastWebhook = new Date(data[0].completed_at);
    const secsSince = (Date.now() - lastWebhook.getTime()) / 1000;
    
    let status = 'healthy';
    if (secsSince > CONFIG.thresholds.webhook_delay_critical) {
      status = 'unhealthy';
    } else if (secsSince > CONFIG.thresholds.webhook_delay_warning) {
      status = 'degraded';
    }
    
    return {
      status,
      lastWebhook,
      secondsSince: Math.round(secsSince),
      message: `Last: ${Math.round(secsSince / 60)}min ago`
    };
  } catch (error) {
    return {
      status: 'unknown',
      message: error.message
    };
  }
}

/**
 * Check server resources
 */
function checkServerResources() {
  const cpuUsage = os.loadavg()[0] / os.cpus().length * 100;
  const totalMem = os.totalmem();
  const freeMem = os.freemem();
  const memUsage = ((totalMem - freeMem) / totalMem) * 100;
  const uptime = os.uptime();
  
  let status = 'healthy';
  const issues = [];
  
  if (cpuUsage > CONFIG.thresholds.cpu_critical) {
    status = 'unhealthy';
    issues.push(`CPU critical: ${cpuUsage.toFixed(1)}%`);
  } else if (cpuUsage > CONFIG.thresholds.cpu_warning) {
    status = 'degraded';
    issues.push(`CPU warning: ${cpuUsage.toFixed(1)}%`);
  }
  
  if (memUsage > CONFIG.thresholds.memory_critical) {
    status = 'unhealthy';
    issues.push(`Memory critical: ${memUsage.toFixed(1)}%`);
  } else if (memUsage > CONFIG.thresholds.memory_warning) {
    if (status !== 'unhealthy') status = 'degraded';
    issues.push(`Memory warning: ${memUsage.toFixed(1)}%`);
  }
  
  return {
    status,
    cpu: cpuUsage.toFixed(1),
    memory: memUsage.toFixed(1),
    uptime: Math.floor(uptime / 3600), // hours
    issues,
    message: `CPU: ${cpuUsage.toFixed(1)}%, Mem: ${memUsage.toFixed(1)}%, Up: ${Math.floor(uptime / 3600)}h`
  };
}

/**
 * Check error rates
 */
async function checkErrorRates() {
  try {
    const hourAgo = new Date(Date.now() - 60 * 60 * 1000).toISOString();
    
    // Get recent submissions
    const { data: submissions } = await supabase
      .from('submissions')
      .select('status')
      .gte('created_at', hourAgo);
    
    if (!submissions || submissions.length < 10) {
      return { status: 'unknown', message: 'Not enough data' };
    }
    
    const failed = submissions.filter(s => s.status === 'failed' || s.status === 'rejected').length;
    const errorRate = failed / submissions.length;
    
    let status = 'healthy';
    if (errorRate > CONFIG.thresholds.error_rate_critical) {
      status = 'unhealthy';
    } else if (errorRate > CONFIG.thresholds.error_rate_warning) {
      status = 'degraded';
    }
    
    return {
      status,
      errorRate: (errorRate * 100).toFixed(1),
      totalChecked: submissions.length,
      message: `${(errorRate * 100).toFixed(1)}% error rate (${submissions.length} samples)`
    };
  } catch (error) {
    return { status: 'unknown', message: error.message };
  }
}

// ═══════════════════════════════════════════════════════════════════════════════
// MAIN HEALTH CHECK
// ═══════════════════════════════════════════════════════════════════════════════

/**
 * Run all health checks
 */
async function runHealthCheck() {
  const startTime = Date.now();
  
  // Run all checks in parallel
  const [database, celo, stripe, server, errors] = await Promise.all([
    checkDatabase(),
    checkCelo(),
    checkStripeWebhook(),
    Promise.resolve(checkServerResources()),
    checkErrorRates()
  ]);
  
  // Compile results
  healthState.services = {
    database,
    celo,
    stripe,
    server,
    errors
  };
  
  // Determine overall status
  const statuses = Object.values(healthState.services).map(s => s.status);
  
  if (statuses.includes('unhealthy')) {
    healthState.status = 'unhealthy';
  } else if (statuses.includes('degraded')) {
    healthState.status = 'degraded';
  } else if (statuses.every(s => s === 'healthy')) {
    healthState.status = 'healthy';
  } else {
    healthState.status = 'unknown';
  }
  
  healthState.lastCheck = new Date().toISOString();
  healthState.checkDuration = Date.now() - startTime;
  
  // Check for alerts
  await checkAndSendAlerts();
  
  return healthState;
}

// ═══════════════════════════════════════════════════════════════════════════════
// ALERTING
// ═══════════════════════════════════════════════════════════════════════════════

const alertCooldowns = new Map();

/**
 * Check conditions and send alerts
 */
async function checkAndSendAlerts() {
  const alerts = [];
  
  for (const [service, status] of Object.entries(healthState.services)) {
    if (status.status === 'unhealthy') {
      alerts.push({
        level: 'critical',
        service,
        message: `${service.toUpperCase()} is DOWN: ${status.message}`
      });
    } else if (status.status === 'degraded') {
      alerts.push({
        level: 'warning',
        service,
        message: `${service.toUpperCase()} degraded: ${status.message}`
      });
    }
  }
  
  // Send alerts that aren't in cooldown
  for (const alert of alerts) {
    const key = `${alert.service}:${alert.level}`;
    const lastAlert = alertCooldowns.get(key);
    
    if (!lastAlert || Date.now() - lastAlert > CONFIG.ALERT_COOLDOWN_MS) {
      await sendAlert(alert);
      alertCooldowns.set(key, Date.now());
    }
  }
  
  healthState.alerts = alerts;
}

/**
 * Send alert to admin
 */
async function sendAlert(alert) {
  console.log(`🚨 ALERT [${alert.level}]: ${alert.message}`);
  
  if (adminBot && ADMIN_TELEGRAM_ID) {
    try {
      const emoji = alert.level === 'critical' ? '🚨' : '⚠️';
      await adminBot.telegram.sendMessage(
        ADMIN_TELEGRAM_ID,
        `${emoji} *LOOPUMAN ALERT*\n\n` +
        `*Level:* ${alert.level.toUpperCase()}\n` +
        `*Service:* ${alert.service}\n` +
        `*Message:* ${alert.message}\n\n` +
        `_${new Date().toISOString()}_`,
        { parse_mode: 'Markdown' }
      );
    } catch (error) {
      console.error('Failed to send Telegram alert:', error.message);
    }
  }
  
  // Log to database for history
  await supabase
    .from('system_alerts')
    .insert({
      level: alert.level,
      service: alert.service,
      message: alert.message,
      created_at: new Date().toISOString()
    });
}

// ═══════════════════════════════════════════════════════════════════════════════
// API ENDPOINTS
// ═══════════════════════════════════════════════════════════════════════════════

/**
 * Create Express router for health endpoints
 */
function createHealthRouter(express) {
  const router = express.Router();
  
  // Simple health check (for load balancers)
  router.get('/health', (req, res) => {
    res.json({
      status: healthState.status,
      timestamp: healthState.lastCheck
    });
  });
  
  // Detailed health status
  router.get('/health/detailed', (req, res) => {
    res.json(healthState);
  });
  
  // Trigger manual health check
  router.post('/health/check', async (req, res) => {
    const result = await runHealthCheck();
    res.json(result);
  });
  
  return router;
}

// ═══════════════════════════════════════════════════════════════════════════════
// DASHBOARD DATA
// ═══════════════════════════════════════════════════════════════════════════════

/**
 * Get health status display for Telegram admin
 */
function getHealthDisplayText() {
  const s = healthState.services;
  
  const statusEmoji = {
    healthy: '✅',
    degraded: '⚠️',
    unhealthy: '❌',
    unknown: '❓'
  };
  
  let text = `🏥 *SYSTEM HEALTH*\n\n`;
  text += `Overall: ${statusEmoji[healthState.status]} ${healthState.status.toUpperCase()}\n`;
  text += `Last Check: ${healthState.lastCheck ? new Date(healthState.lastCheck).toLocaleTimeString() : 'Never'}\n\n`;
  
  text += `*Services*\n`;
  text += `${statusEmoji[s.database?.status]} Database: ${s.database?.message || 'Unknown'}\n`;
  text += `${statusEmoji[s.celo?.status]} Celo: ${s.celo?.message || 'Unknown'}\n`;
  text += `${statusEmoji[s.stripe?.status]} Stripe: ${s.stripe?.message || 'Unknown'}\n`;
  text += `${statusEmoji[s.server?.status]} Server: ${s.server?.message || 'Unknown'}\n`;
  text += `${statusEmoji[s.errors?.status]} Errors: ${s.errors?.message || 'Unknown'}\n`;
  
  if (healthState.alerts.length > 0) {
    text += `\n⚠️ *Active Alerts*\n`;
    healthState.alerts.forEach(a => {
      text += `• ${a.message}\n`;
    });
  }
  
  return text;
}

// ═══════════════════════════════════════════════════════════════════════════════
// INITIALIZATION
// ═══════════════════════════════════════════════════════════════════════════════

/**
 * Initialize health monitoring
 */
function initialize(bot = null) {
  adminBot = bot;
  
  // Run initial check
  runHealthCheck();
  
  // Schedule periodic checks
  setInterval(runHealthCheck, CONFIG.CHECK_INTERVAL_MS);
  
  console.log('✅ Health monitoring initialized');
}

// ═══════════════════════════════════════════════════════════════════════════════
// EXPORTS
// ═══════════════════════════════════════════════════════════════════════════════

module.exports = {
  // Core
  initialize,
  runHealthCheck,
  
  // Individual checks
  checkDatabase,
  checkCelo,
  checkStripeWebhook,
  checkServerResources,
  checkErrorRates,
  
  // Alerting
  sendAlert,
  
  // API
  createHealthRouter,
  
  // Display
  getHealthDisplayText,
  
  // State
  getState: () => healthState,
  
  // Config
  CONFIG
};
