namespace :mongo do

desc "Show list of available backup files"
task :list_backups => :environment do
  backups.each { |file| puts file.key.gsub('backups/', '') }
end

desc "Restore database from backup"
task :restore => :environment do
  if ENV['FILE']
    restore(ENV['FILE'])
  else
    filename = backups.last.key.gsub('backups/', '')
    restore(filename)
  end
end

desc "Backup database and upload to S3 bucket"
task :backup => :environment do
  # TODO: check if mongodump command is installed on a server
  # sudo apt-get install mongodb-clients

  uri, db_name = parse_uri()
  filename     = Time.now.strftime("%Y-%m-%d_%H-%M-%S.tar.gz")
  if uri.user
    backup_cmd   = "mongodump -u #{uri.user} -p #{uri.password} -h #{uri.host}:#{uri.port} -d #{db_name}"
  else
    backup_cmd   = "mongodump -h #{uri.host}:#{uri.port} -d #{db_name}"
  end

  system "cd /tmp ; #{backup_cmd} ; GZIP=-9 tar -zcvf #{filename} dump/"

  bucket.files.create(key: "backups/#{filename}", body: open("/tmp/#{filename}"))

  system "rm /tmp/#{filename} ; rm -Rf /tmp/dump"
end

private

def connection
  @connection ||= Fog::Storage.new({ provider:              'AWS',
                                     aws_access_key_id:     ENV['AWS_ACCESS_KEY_ID'],
                                     aws_secret_access_key: ENV['AWS_SECRET_ACCESS_KEY'] })
end

def backups
  connection.directories.get(ENV['S3_BACKUPS_BUCKET'], prefix: 'backups').files
end

def bucket
  connection.directories.new(key: ENV['S3_BACKUPS_BUCKET'])
end

def restore(filename)
  s3_file  = bucket.files.get("backups/#{filename}")
  db_name  = ::Mongoid::Sessions.default.options[:database]

  open("/tmp/#{filename}", 'w') { |f| f.binmode ; f.write s3_file.body }

  system "cd /tmp ; tar -xzf /tmp/#{filename}"

  ::Mongoid::Sessions.default.drop

  if Rails.env.production?
    uri, backup_db_name = parse_uri()
    if uri.user
      system "mongorestore -u #{uri.user} -p #{uri.password} -h #{uri.host}:#{uri.port} -d #{db_name} /tmp/dump/#{backup_db_name}"
    else
      system "mongorestore -h #{uri.host}:#{uri.port} -d #{db_name} /tmp/dump/#{backup_db_name}"
    end
  else
    backup_db_name = Dir.entries('/tmp/dump').select { |file| File.directory? File.join('/tmp/dump', file) }.last
    system "mongorestore -d #{db_name} /tmp/dump/#{backup_db_name}"
  end

  system "rm /tmp/#{filename} ; rm -Rf /tmp/dump"
end

def parse_uri
  db_url = ENV['MONGODB_URL'] || ENV['MONGO_URL'] || ENV['MONGODB_URI']

  if db_url.nil?
    puts "ENV['MONGODB_URL'] has to be defined."
    exit
  end

  # use first mongodb server if a few provided
  first_uri = db_url.split(',').first
  uri       = URI.parse(first_uri)
  db_name   = Mongoid.default_session.options[:database]

  return uri, db_name
end

# TODO: sync for c66:
# 1. Get mongo database uri from c66 via API or toolbelt (if possible or clone and make a feature)
# 2. Check if possible to use with mongodump
# 3. Parse uri and pass values to mongodump command if not possible usage of uri with mongodump
# 4. Execute all backup commands with proper values

#"""mongodump -u admin -p '' -h ds029120-a0.mongolab.com:29120 -d wta
#   mongo wta --eval "db.dropDatabase()"
#   mongorestore dump/wta"""

end