# frozen_string_literal: true

class GenerateMissingRoutesForBots < ActiveRecord::Migration[6.0]
  DOWNTIME = false

  disable_ddl_transaction!

  class User < ActiveRecord::Base
    self.table_name = 'users'

    USER_TYPES = {
      human: nil,
      support_bot: 1,
      alert_bot: 2,
      visual_review_bot: 3,
      service_user: 4,
      ghost: 5,
      project_bot: 6,
      migration_bot: 7
    }.with_indifferent_access.freeze

    BOT_USER_TYPES = %w[alert_bot project_bot support_bot visual_review_bot migration_bot].freeze

    scope :bots, -> { where(user_type: USER_TYPES.values_at(*BOT_USER_TYPES)) }
  end

  class Route < ActiveRecord::Base
    self.table_name = 'routes'

    validates :path,
      uniqueness: { case_sensitive: false }
  end

  class Namespace < ActiveRecord::Base
    self.table_name = 'namespaces'

    belongs_to :owner, class_name: 'GenerateMissingRoutesForBots::User'

    scope :for_user, -> { where('type IS NULL') }
    scope :for_bots, -> { for_user.joins(:owner).merge(GenerateMissingRoutesForBots::User.bots) }

    scope :without_routes, -> do
      where(
        'NOT EXISTS (
          SELECT 1
          FROM routes
          WHERE source_type = ?
          AND source_id = namespaces.id
        )',
          self.source_type_for_route
      )
    end

    def self.source_type_for_route
      'Namespace'
    end

    def attributes_for_insert
      {
        source_type: self.class.source_type_for_route,
        source_id: id,
        name: name,
        path: path
      }
    end
  end

  def up
    # Reset the column information of all the models that update the database
    # to ensure the Active Record's knowledge of the table structure is current
    Route.reset_column_information

    logger = Gitlab::BackgroundMigration::Logger.build
    attributes_to_be_logged = %w(id path name)

    GenerateMissingRoutesForBots::Namespace.for_bots.without_routes.each do |namespace|
      route = GenerateMissingRoutesForBots::Route.create(namespace.attributes_for_insert)
      namespace_details = namespace.as_json.slice(*attributes_to_be_logged)

      if route.persisted?
        logger.info namespace_details.merge(message: 'a new route was created for the namespace')
      else
        errors = route.errors.full_messages.join(',')
        logger.info namespace_details.merge(message: 'route creation failed for the namespace', errors: errors)
      end
    end
  end

  def down
    # no op
  end
end
