package com.gnx.telemedicine.health;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.stereotype.Component;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.HashMap;
import java.util.Map;

/**
 * Custom health indicator for database connectivity and performance.
 */
@Component
@RequiredArgsConstructor
@Slf4j
public class DatabaseHealthIndicator implements HealthIndicator {

    private final DataSource dataSource;

    @Override
    public Health health() {
        Map<String, Object> details = new HashMap<>();
        
        try (Connection connection = dataSource.getConnection()) {
            // Check connection validity
            boolean isValid = connection.isValid(5); // 5 second timeout
            
            if (!isValid) {
                return Health.down()
                        .withDetail("status", "Connection validation failed")
                        .withDetail("database", "PostgreSQL")
                        .build();
            }
            
            // Get database metadata
            DatabaseMetaData metaData = connection.getMetaData();
            details.put("database", metaData.getDatabaseProductName());
            details.put("version", metaData.getDatabaseProductVersion());
            details.put("driver", metaData.getDriverName());
            details.put("driverVersion", metaData.getDriverVersion());
            details.put("url", metaData.getURL());
            details.put("username", metaData.getUserName());
            
            // Test query performance
            long startTime = System.currentTimeMillis();
            try (Statement statement = connection.createStatement();
                 ResultSet rs = statement.executeQuery("SELECT 1")) {
                if (rs.next()) {
                    long queryTime = System.currentTimeMillis() - startTime;
                    details.put("queryTime", queryTime + "ms");
                    
                    if (queryTime > 1000) {
                        return Health.up()
                                .withDetails(details)
                                .withDetail("status", "UP")
                                .withDetail("warning", "Query response time is slow: " + queryTime + "ms")
                                .build();
                    }
                }
            }
            
            // Check connection pool status (if HikariCP)
            if (dataSource instanceof com.zaxxer.hikari.HikariDataSource) {
                com.zaxxer.hikari.HikariDataSource hikariDataSource = 
                        (com.zaxxer.hikari.HikariDataSource) dataSource;
                com.zaxxer.hikari.HikariPoolMXBean poolBean = hikariDataSource.getHikariPoolMXBean();
                
                details.put("activeConnections", poolBean.getActiveConnections());
                details.put("idleConnections", poolBean.getIdleConnections());
                details.put("totalConnections", poolBean.getTotalConnections());
                details.put("threadsAwaitingConnection", poolBean.getThreadsAwaitingConnection());
                
                // Warn if connection pool is exhausted
                if (poolBean.getThreadsAwaitingConnection() > 0) {
                    return Health.up()
                            .withDetails(details)
                            .withDetail("status", "UP")
                            .withDetail("warning", "Connection pool has waiting threads")
                            .build();
                }
            }
            
            return Health.up()
                    .withDetails(details)
                    .withDetail("status", "UP")
                    .build();
                    
        } catch (Exception e) {
            log.error("Database health check failed", e);
            return Health.down()
                    .withDetail("status", "DOWN")
                    .withDetail("error", e.getMessage())
                    .withDetail("database", "PostgreSQL")
                    .withException(e)
                    .build();
        }
    }
}

