module Gitlab
  module Geo
    class HealthCheck
      def self.perform_checks
        return '' unless Gitlab::Geo.secondary?
        return 'The Geo secondary role is disabled.' unless Gitlab::Geo.secondary_role_enabled?
        return 'The Geo database configuration file is missing.' unless self.geo_database_configured?
        return 'The Geo node has a database that is not configured for streaming replication with the primary node.' unless self.database_secondary?

        database_version  = self.get_database_version.to_i
        migration_version = self.get_migration_version.to_i

        if database_version != migration_version
          "Current Geo database version (#{database_version}) does not match latest migration (#{migration_version})."
        else
          ''
        end
      rescue => e
        e.message
      end

      def self.db_migrate_path
        # Lazy initialisation so Rails.root will be defined
        @db_migrate_path ||= File.join(Rails.root, 'db', 'geo', 'migrate')
      end

      def self.get_database_version
        if defined?(ActiveRecord)
          connection = ::Geo::BaseRegistry.connection
          schema_migrations_table_name = ActiveRecord::Base.schema_migrations_table_name

          if connection.table_exists?(schema_migrations_table_name)
            connection.execute("SELECT MAX(version) AS version FROM #{schema_migrations_table_name}")
                      .first
                      .fetch('version')
          end
        end
      end

      def self.get_migration_version
        latest_migration = nil

        Dir[File.join(self.db_migrate_path, "[0-9]*_*.rb")].each do |f|
          timestamp = f.scan(/0*([0-9]+)_[_.a-zA-Z0-9]*.rb/).first.first rescue -1

          if latest_migration.nil? || timestamp.to_i > latest_migration.to_i
            latest_migration = timestamp
          end
        end

        latest_migration
      end

      def self.database_secondary?
        raise NotImplementedError unless Gitlab::Database.postgresql?

        ActiveRecord::Base.connection.execute('SELECT pg_is_in_recovery()')
          .first
          .fetch('pg_is_in_recovery') == 't'
      end

      def self.geo_database_configured?
        Rails.configuration.respond_to?(:geo_database)
      end
    end
  end
end