import { getLogger } from '@stock-bot/logger';
import type { PostgreSQLClient } from './client';
import type { PostgreSQLHealthCheck, PostgreSQLHealthStatus, PostgreSQLMetrics } from './types';

/**
 * PostgreSQL Health Monitor
 *
 * Monitors PostgreSQL connection health and provides metrics
 */
export class PostgreSQLHealthMonitor {
  private readonly client: PostgreSQLClient;
  private readonly logger: ReturnType<typeof getLogger>;
  private healthCheckInterval: NodeJS.Timeout | null = null;
  private metrics: PostgreSQLMetrics;
  private lastHealthCheck: PostgreSQLHealthCheck | null = null;

  constructor(client: PostgreSQLClient) {
    this.client = client;
    this.logger = getLogger('postgres-health-monitor');
    this.metrics = {
      queriesPerSecond: 0,
      averageQueryTime: 0,
      errorRate: 0,
      connectionPoolUtilization: 0,
      slowQueries: 0,
    };
  }

  /**
   * Start health monitoring
   */
  start(intervalMs: number = 30000): void {
    if (this.healthCheckInterval) {
      this.stop();
    }

    this.logger.info(`Starting PostgreSQL health monitoring (interval: ${intervalMs}ms)`);

    this.healthCheckInterval = setInterval(async () => {
      try {
        await this.performHealthCheck();
      } catch (error) {
        this.logger.error('Health check failed:', error);
      }
    }, intervalMs);

    // Perform initial health check
    this.performHealthCheck().catch(error => {
      this.logger.error('Initial health check failed:', error);
    });
  }

  /**
   * Stop health monitoring
   */
  stop(): void {
    if (this.healthCheckInterval) {
      clearInterval(this.healthCheckInterval);
      this.healthCheckInterval = null;
      this.logger.info('Stopped PostgreSQL health monitoring');
    }
  }

  /**
   * Get current health status
   */
  async getHealth(): Promise<PostgreSQLHealthCheck> {
    if (!this.lastHealthCheck) {
      await this.performHealthCheck();
    }
    if (!this.lastHealthCheck) {
      throw new Error('Health check failed to produce results');
    }
    return this.lastHealthCheck;
  }

  /**
   * Get current metrics
   */
  getMetrics(): PostgreSQLMetrics {
    return { ...this.metrics };
  }

  /**
   * Perform a health check
   */
  private async performHealthCheck(): Promise<void> {
    const startTime = Date.now();
    const errors: string[] = [];
    let status: PostgreSQLHealthStatus = 'healthy';

    try {
      if (!this.client.connected) {
        errors.push('PostgreSQL client not connected');
        status = 'unhealthy';
      } else {
        // Test basic connectivity
        await this.client.query('SELECT 1');

        // Get connection stats
        const stats = await this.client.getStats();

        // Check connection pool utilization
        const utilization = parseInt(stats.active_connections) / parseInt(stats.max_connections);
        if (utilization > 0.8) {
          errors.push('High connection pool utilization');
          status = status === 'healthy' ? 'degraded' : status;
        }

        // Check for high latency
        const latency = Date.now() - startTime;
        if (latency > 1000) {
          errors.push(`High latency: ${latency}ms`);
          status = status === 'healthy' ? 'degraded' : status;
        }

        this.metrics.connectionPoolUtilization = utilization;
      }
    } catch (error) {
      errors.push(`Health check failed: ${(error as Error).message}`);
      status = 'unhealthy';
    }

    const latency = Date.now() - startTime;

    this.lastHealthCheck = {
      status,
      timestamp: new Date(),
      latency,
      connections: {
        active: 1,
        idle: 9,
        total: 10,
      },
      errors: errors.length > 0 ? errors : undefined,
    };

    // Log health status changes
    if (status !== 'healthy') {
      this.logger.warn(`PostgreSQL health status: ${status}`, { errors, latency });
    } else {
      this.logger.debug(`PostgreSQL health check passed (${latency}ms)`);
    }
  }
}
