package com.honey.honey.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.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

@Slf4j
@Component
@RequiredArgsConstructor
public class DatabaseHealthIndicator implements HealthIndicator {

    private final DataSource dataSource;

    @Override
    public Health health() {
        try (Connection connection = dataSource.getConnection()) {
            if (!connection.isValid(1)) {
                return Health.down()
                        .withDetail("database", "MySQL")
                        .withDetail("status", "Connection invalid")
                        .build();
            }

            // Check if Flyway schema history table exists and migrations are complete
            // This ensures migrations have run before health check passes
            boolean migrationsComplete = checkFlywayMigrations(connection);

            if (migrationsComplete) {
                return Health.up()
                        .withDetail("database", "MySQL")
                        .withDetail("status", "Connected")
                        .withDetail("migrations", "Complete")
                        .build();
            } else {
                // Migrations not complete yet - return DOWN to prevent health check from passing
                return Health.down()
                        .withDetail("database", "MySQL")
                        .withDetail("status", "Connected")
                        .withDetail("migrations", "Pending")
                        .build();
            }
        } catch (SQLException e) {
            log.error("Database health check failed", e);
            return Health.down()
                    .withDetail("database", "MySQL")
                    .withDetail("error", e.getMessage())
                    .build();
        }
    }

    /**
     * Checks if Flyway migrations are complete by verifying:
     * 1. The flyway_schema_history table exists
     * 2. There are no pending migrations (all migrations have been applied)
     * 
     * This prevents the health check from passing before migrations complete,
     * which is important during rolling updates when both old and new containers
     * might be running simultaneously.
     */
    private boolean checkFlywayMigrations(Connection connection) {
        try {
            // Check if flyway_schema_history table exists
            // Flyway creates this table in the same database as the application
            String checkTableQuery = "SELECT COUNT(*) as count FROM information_schema.tables " +
                    "WHERE table_schema = DATABASE() AND table_name = 'flyway_schema_history'";
            
            try (PreparedStatement stmt = connection.prepareStatement(checkTableQuery);
                 ResultSet rs = stmt.executeQuery()) {
                
                if (!rs.next() || rs.getInt("count") == 0) {
                    // Table doesn't exist yet - migrations haven't started
                    log.debug("Flyway schema history table not found - migrations not started");
                    return false;
                }
            }

            // Check if there are any pending migrations
            // Pending migrations have success = 0 or don't exist in the history
            // We check by comparing the installed_rank with the expected count
            // If all migrations are applied, the highest installed_rank should match the total
            String checkPendingQuery = "SELECT " +
                    "(SELECT COUNT(*) FROM flyway_schema_history WHERE success = 1) as applied, " +
                    "(SELECT MAX(installed_rank) FROM flyway_schema_history WHERE success = 1) as max_rank, " +
                    "(SELECT COUNT(*) FROM flyway_schema_history) as total";
            
            try (PreparedStatement stmt = connection.prepareStatement(checkPendingQuery);
                 ResultSet rs = stmt.executeQuery()) {
                
                if (rs.next()) {
                    int applied = rs.getInt("applied");
                    int maxRank = rs.getInt("max_rank");
                    int total = rs.getInt("total");
                    
                    // If there are failed migrations (total > applied), migrations are not complete
                    if (total > applied) {
                        log.warn("Flyway migrations incomplete: {} applied, {} total (some failed)", applied, total);
                        return false;
                    }
                    
                    // If max_rank is 0 and total is 0, no migrations have run yet
                    if (maxRank == 0 && total == 0) {
                        log.debug("No Flyway migrations found in history");
                        return false;
                    }
                    
                    // All migrations applied successfully
                    log.debug("Flyway migrations complete: {} migrations applied", applied);
                    return true;
                }
            }
            
            return false;
        } catch (SQLException e) {
            // If we can't check migrations, assume they're not complete
            // This is safer than assuming they are complete
            log.warn("Could not check Flyway migration status: {}", e.getMessage());
            return false;
        }
    }
}


