# rubocop:disable all require 'yaml' require 'json' require 'shellwords'

namespace :db do

task :load_from_remote do |t, _|
  RemoteDbLoader.new.call
end

end

class RemoteDbLoader

def call
  env = 'staging'
  env = ENV['SERVER'] if ENV['SERVER'].present?

  to_be_rsync_folder = ENV['SYNC_FOLDER']

  database_yml =
    "#{Rails.root}/config/database.yml"
  development_db = YAML.load_file(database_yml)[ENV['RAILS_ENV'] || 'development']

  username = development_db['username'] || 'root'
  password = development_db['password']
  database = development_db['database']
  host = development_db['host'] || 'localhost'

  begin
    eval File.read("#{Rails.root}/config/deploy.rb")
  rescue LoadError
  end
  eval File.read("#{Rails.root}/config/deploy/#{env}.rb")
  port = @port || 22

  ## get remote database config.yml
  puts "ssh #{@server_user}@#{@server_ip} -p#{port} which ruby"
  ruby_cmd = `ssh #{@server_user}@#{@server_ip} -p#{port} which ruby`.strip
  if ruby_cmd.blank?
    ruby_cmd = "/home/#{@server_user}/.rbenv/shims/ruby"
  end
  get_db_info_command = %{ssh #{@server_user}@#{@server_ip} -p#{port} \
  "#{ruby_cmd} -e \
  \\"require 'yaml'; \
  puts YAML.load_file('#{@deploy_to}/shared/config/database.yml')['#{env}']\\""}

  shared_path = ENV['TEMP_STORED_FOLDER'] || "#{@deploy_to}/shared"

  puts get_db_info_command
  remote_db_config = eval `#{get_db_info_command}`
  remote_db_host = remote_db_config["host"] || 'localhost'
  remote_db_name = remote_db_config["database"]
  remote_db_username = remote_db_config["username"] || 'root'
  remote_db_password = remote_db_config["password"]

  ## run the real backup
  puts 'Running the remote backup...'
  mysql_cmd = "mysqldump -u #{remote_db_username} -p'#{remote_db_password}' \
  -h #{remote_db_host} #{remote_db_name} > \
  #{shared_path}/backup.sql".shellescape
  backup_command = %(ssh #{@server_user}@#{@server_ip} -p#{port} #{mysql_cmd})
  system(backup_command)

  check_gzip_exist_cmd = 'which gzip'
  check_gzip_exist_remote_cmd =
    %(ssh #{@server_user}@#{@server_ip} -p#{port} #{check_gzip_exist_cmd})

  puts 'Checking for remote gzip location...'
  gzip_exist = system(check_gzip_exist_remote_cmd) != ''

  if gzip_exist
    puts 'zipping remote backup file...'
    zip_cmd = "gzip -f #{shared_path}/backup.sql"
    zip_cmd_remote =
      %(ssh #{@server_user}@#{@server_ip} -p#{port} #{zip_cmd})
    system(zip_cmd_remote)
  end

  puts 'Downloading remote backup file...'
  bk_extension = gzip_exist ? 'sql.gz' : 'sql'
  download_db_dump_command =
    %(scp -P#{port} #{@server_user}@#{@server_ip}:#{shared_path}/backup.#{bk_extension} .)

  system(download_db_dump_command)

  puts 'Deleting remote backup file...'
  delete_db_dump_command = %(ssh #{@server_user}@#{@server_ip} -p#{port} \
  "rm -rf #{shared_path}/backup.#{bk_extension}")

  system(delete_db_dump_command)

  if gzip_exist
    `gunzip -f backup.sql.gz`
  end

  if ENV['DOWNLOAD_ONLY']
    puts 'backup.sql file is now stored at your Rails root folder!'
    `open .`
  else
    # run db create in case the db does not exist
    `bundle exec rake db:create`

    if password == nil
      import_db_cmd =
        %(mysql -u #{username} #{database} -h #{host} < backup.sql)
    else
      import_db_cmd =
        %(mysql -u #{username} -p'#{password}' -h #{host} #{database} < backup.sql)
    end

    puts 'Importing database into local environment...'
    `#{import_db_cmd}`

    puts 'Cleaning up database backup...'
    `rm backup.sql`
  end

  if to_be_rsync_folder
    puts "Synchorinizing #{to_be_rsync_folder} folder..."
    `mkdir -p #{to_be_rsync_folder}`
    sync_folder_cmd = %(rsync -r \

#{@server_user}@#{@server_ip}:#{shared_path}/#{to_be_rsync_folder}/ \ #{to_be_rsync_folder})

    puts sync_folder_cmd
    system(sync_folder_cmd)
  end

  puts 'DONE!'
end

def method_missing(name, *args, &block)
  if name == :fetch && (args[0] == :deploy_user || args[0] == :user)
    return @server_user
  end

  if name == :fetch && args[0] == :application
    return @application
  end

  if name == :fetch && args[0] == :full_app_name
    return @full_app_name
  end

  if name == :fetch && args[0] == :stage
    return @stage
  end

  return self unless %I[server set].include?(name)
  @server_ip ||= if name == :server
                   args[0]
                 elsif name == :set && args[0] == :domain
                   args[1]
                 end
  @server_user ||= args[1] if name == :set && args[0] == :user
  @stage ||= args[1] if name == :set && args[0] == :stage
  @server_user = args[1] if name == :set && args[0] == :deploy_user
  @application ||= args[1] if name == :set && args[0] == :application
  @full_app_name ||= args[1] if name == :set && args[0] == :full_app_name
  @port ||= args[1] if name == :set && args[0] == :port
  if name == :set && args[0] == :deploy_to
    puts args[1]
    @deploy_to ||= args[1]
  end
end

end