require "#{base_path}/embedded/service/omnibus-ctl-ee/lib/geo/replication"
require 'optparse'
require 'English'

add_command_under_category('replicate-geo-database', 'gitlab-geo', 'Replicate Geo database', 2) do |_cmd_name, *args|
  GeoReplicationCommand.new(self, ARGV).execute!
end

class GeoReplicationCommand
  def initialize(ctl, args)
    @ctl = ctl
    @args = args

    @options = {
      user: 'gitlab_replicator',
      port: 5432,
      host: nil,
      password: nil,
      now: false,
      force: false,
      skip_backup: false,
      slot_name: nil,
      skip_replication_slot: false,
      backup_timeout: 1800,
      sslmode: 'verify-full',
      sslcompression: 0,
      recovery_target_timeline: 'latest',
      db_name: 'gitlabhq_production'
    }

    parse_options!
  end

  def execute!
    Geo::Replication.new(@ctl, @options).execute
  end

  def arguments
    @args.dup
  end

  private

  def parse_options!
    opts_parser = OptionParser.new do |opts|
      opts.banner = 'Usage: gitlab-ctl replicate-geo-database [options]'

      opts.separator ''
      opts.separator 'Specific @options:'

      opts.on('--host=HOST', 'Hostname address of the primary node') do |host|
        @options[:host] = host
      end

      opts.on('--user[=USER]', 'Specify a different replication user') do |user|
        @options[:user] = user
      end

      opts.on('--port[=PORT]', 'Specify a different PostgreSQL port') do |port|
        @options[:port] = port
      end

      opts.on('--slot-name[=SLOT-NAME]', 'PostgreSQL replication slot name') do |slot_name|
        @options[:slot_name] = slot_name
      end

      opts.on('--no-wait', 'Do not ask for confirmation before starting the replication process') do
        @options[:now] = true
      end

      opts.on('--backup-timeout[=BACKUP_TIMEOUT]', 'Specify the timeout for the initial database backup from the primary') do |backup_timeout|
        @options[:backup_timeout] = backup_timeout.to_i
      end

      opts.on('--force', 'Disable existing database even if instance is not empty') do
        @options[:force] = true
      end

      opts.on('--skip-backup', 'Skip the backup before starting the replication process') do
        @options[:skip_backup] = true
      end

      opts.on('--skip-replication-slot', 'Skip the check and creation of replication slot') do
        @options[:skip_replication_slot] = true
      end

      opts.on('--sslmode=MODE', 'Choose the level of protection the connection between primary and secondary has') do |sslmode|
        @options[:sslmode] = sslmode
      end

      opts.on('--sslcompression=1', 'Enable SSL compression (disabled by default for performance and security)') do |sslcompression|
        @options[:sslcompression] = sslcompression.to_i
      end

      opts.on('--recovery-target-timeline=latest', 'Specify the PostgreSQL recovery target timeline (see https://www.postgresql.org/docs/12/recovery-target-settings.html)') do |timeline|
        @options[:recovery_target_timeline] = timeline
      end

      opts.on('--db_name=gitlabhq_production', 'Specify the database name') do |db_name|
        @options[:db_name] = db_name
      end

      opts.on_tail('-h', '--help', 'Show this message') do
        puts opts
        exit
      end
    end

    opts_parser.parse!(arguments)

    raise OptionParser::MissingArgument, :host unless @options.fetch(:host)
    raise OptionParser::MissingArgument, '--slot-name' unless @options[:skip_replication_slot] || @options.fetch(:slot_name)
  rescue OptionParser::InvalidOption, OptionParser::MissingArgument
    puts $ERROR_INFO.to_s
    puts opts_parser
    exit 1
  end
end
