/**
 * Health Check Endpoint
 * Provides system health status for monitoring and load balancers.
 * Ported from Python deployment/health_check.py
 */

import os from 'os';
import { getConnection } from '../database/pool.js';

// ============================================================================
// Types
// ============================================================================

export type HealthStatus = 'healthy' | 'degraded' | 'unhealthy' | 'unknown';

export interface ComponentHealth {
  status: HealthStatus;
  latency_ms?: number | null;
  error?: string;
  warning?: string | null;
  [key: string]: unknown;
}

export interface MemoryHealth extends ComponentHealth {
  used_percent?: number;
  used_mb?: number;
  free_mb?: number;
  total_mb?: number;
}

export interface DiskHealth extends ComponentHealth {
  used_percent?: number;
  used_gb?: number;
  free_gb?: number;
  total_gb?: number;
}

export interface WebSocketHealth extends ComponentHealth {
  active: number;
  max: number;
  usage_percent: number;
}

export interface FullHealthCheck {
  status: HealthStatus;
  timestamp: number;
  uptime_seconds: number;
  checks: {
    database: ComponentHealth;
    memory: MemoryHealth;
    websockets: WebSocketHealth;
  };
}

// ============================================================================
// Health Checker Class
// ============================================================================

/**
 * Performs health checks on various system components.
 */
export class HealthChecker {
  private startTime: number;
  private lastCheck: Record<string, unknown> = {};

  constructor() {
    this.startTime = Date.now();
  }

  /**
   * Get server uptime in seconds.
   */
  getUptime(): number {
    return (Date.now() - this.startTime) / 1000;
  }

  /**
   * Check database connectivity and performance.
   */
  async checkDatabase(): Promise<ComponentHealth> {
    const start = Date.now();
    let connection;

    try {
      connection = await getConnection();

      // Execute simple query to test connectivity
      await connection.execute('SELECT 1');

      const latency = Date.now() - start;

      return {
        status: latency < 100 ? 'healthy' : 'degraded',
        latency_ms: latency,
        warning: latency > 100 ? 'High latency' : null,
      };
    } catch (error) {
      console.error('Database health check failed:', error);
      return {
        status: 'unhealthy',
        error: error instanceof Error ? error.message : 'Unknown error',
        latency_ms: null,
      };
    } finally {
      if (connection) {
        connection.release();
      }
    }
  }

  /**
   * Check memory usage.
   */
  checkMemory(): MemoryHealth {
    try {
      const totalMem = os.totalmem();
      const freeMem = os.freemem();
      const usedMem = totalMem - freeMem;
      const usedPercent = (usedMem / totalMem) * 100;

      let status: HealthStatus = 'healthy';
      if (usedPercent > 90) {
        status = 'unhealthy';
      } else if (usedPercent > 80) {
        status = 'degraded';
      }

      return {
        status,
        used_percent: Math.round(usedPercent * 100) / 100,
        used_mb: Math.round(usedMem / 1024 / 1024),
        free_mb: Math.round(freeMem / 1024 / 1024),
        total_mb: Math.round(totalMem / 1024 / 1024),
      };
    } catch (error) {
      console.error('Memory check failed:', error);
      return {
        status: 'unknown',
        error: error instanceof Error ? error.message : 'Unknown error',
      };
    }
  }

  /**
   * Check WebSocket connection health.
   */
  checkWebSocketConnections(
    activeConnections: number,
    maxConnections = 1000
  ): WebSocketHealth {
    const usagePercent = (activeConnections / maxConnections) * 100;

    let status: HealthStatus = 'healthy';
    if (usagePercent > 95) {
      status = 'unhealthy';
    } else if (usagePercent > 90) {
      status = 'degraded';
    }

    return {
      status,
      active: activeConnections,
      max: maxConnections,
      usage_percent: Math.round(usagePercent * 100) / 100,
    };
  }

  /**
   * Perform a comprehensive health check.
   */
  async performFullCheck(activeConnections = 0): Promise<FullHealthCheck> {
    const [database, memory] = await Promise.all([
      this.checkDatabase(),
      Promise.resolve(this.checkMemory()),
    ]);

    const websockets = this.checkWebSocketConnections(activeConnections);

    const checks = {
      database,
      memory,
      websockets,
    };

    // Determine overall status
    const statuses = Object.values(checks).map((check) => check.status);
    let overallStatus: HealthStatus = 'healthy';

    if (statuses.includes('unhealthy')) {
      overallStatus = 'unhealthy';
    } else if (statuses.includes('degraded')) {
      overallStatus = 'degraded';
    } else if (statuses.includes('unknown')) {
      overallStatus = 'unknown';
    }

    return {
      status: overallStatus,
      timestamp: Date.now(),
      uptime_seconds: Math.round(this.getUptime() * 100) / 100,
      checks,
    };
  }
}

// ============================================================================
// Global Instance
// ============================================================================

let healthChecker: HealthChecker | null = null;

export function getHealthChecker(): HealthChecker {
  if (!healthChecker) {
    healthChecker = new HealthChecker();
  }
  return healthChecker;
}

// ============================================================================
// Kubernetes-style Probes
// ============================================================================

/**
 * Simple liveness probe - checks if the service is running.
 */
export async function livenessProbe(): Promise<boolean> {
  try {
    const checker = getHealthChecker();
    checker.getUptime();
    return true;
  } catch (error) {
    console.error('Liveness probe failed:', error);
    return false;
  }
}

/**
 * Readiness probe - checks if the service is ready to accept traffic.
 */
export async function readinessProbe(activeConnections = 0): Promise<boolean> {
  try {
    const checker = getHealthChecker();
    const health = await checker.performFullCheck(activeConnections);
    // Ready if status is healthy or degraded (but not unhealthy)
    return health.status === 'healthy' || health.status === 'degraded';
  } catch (error) {
    console.error('Readiness probe failed:', error);
    return false;
  }
}

// ============================================================================
// Express/HTTP Handler
// ============================================================================

/**
 * Create an Express-compatible health check handler.
 *
 * Usage with Express:
 *   app.get('/health', createHealthHandler());
 */
export function createHealthHandler() {
  return async (
    req: { query?: { connections?: string } },
    res: { status: (code: number) => { json: (data: unknown) => void } }
  ): Promise<void> => {
    const connections = parseInt(req.query?.connections || '0', 10);
    const checker = getHealthChecker();
    const status = await checker.performFullCheck(connections);
    const httpCode = status.status === 'healthy' ? 200 : 503;
    res.status(httpCode).json(status);
  };
}

// ============================================================================
// Export
// ============================================================================

export const healthCheck = {
  HealthChecker,
  getHealthChecker,
  livenessProbe,
  readinessProbe,
  createHealthHandler,
};
