require_relative '../tools/disclaimer' require_relative '../tools/terminal' require_relative '../tools/database' require_relative '../tools/s3_storage' require 'tty-prompt' require 'tty-spinner' require 'pastel'

namespace :postgresql_backup do

desc 'Dumps the database'
task dump: :environment do
  title = pastel.yellow.bold('POSTGRESQL BACKUP')
  text = 'You are about to backup your database. Relax on your seat, this process is usually fast and you don\'t need to do anything except wait for the process to end. Here is the current configuration for this backup:'
  texts = [text, ' ', configuration_to_text].flatten
  disclaimer.show(title: title, texts: texts)

  file_path = Tools::Terminal.spinner('Backing up database') { db.dump }

  if configuration.s3?
    Tools::Terminal.spinner('Uploading file') { storage.upload(file_path) }
    Tools::Terminal.spinner('Deleting local file') { File.delete(file_path) }  if File.exist?(file_path)
  end

  puts ''
  puts pastel.green('All done.')
end

desc 'Restores a database backup into the database'
task restore: :environment do
  title = pastel.green('POSTGRESQL DATABASE RESTORE')
  text = 'Let\'s get your data back. You will be prompted to choose the file to restore, but that\'s all, you can leave the rest to us. Here is the current configuration for this restore:'
  texts = [text, ' ', configuration_to_text].flatten
  disclaimer.show(title: title, texts: texts)
  local_file_path = ''

  files = Tools::Terminal.spinner('Loading backups list') { list_backup_files }

  if files.present?
    puts ''
    file_name = prompt.select("Choose the file to restore", files)
    puts ''

    if configuration.s3?
      local_file_path = Tools::Terminal.spinner('Downloading file') { storage.download(file_name) }
    end

    db.reset

    Tools::Terminal.spinner('Restoring data') { db.restore(file_name) }

    if configuration.s3?
      Tools::Terminal.spinner('Deleting local file') { File.delete(local_file_path) }
    end

    puts ''
    puts pastel.green('All done.')
  else
    spinner = TTY::Spinner.new("#{pastel.yellow("[:spinner] ")}Restoring data...")
    error_message = "#{pastel.red.bold('failed')}. Backup files not found."
    spinner.success(error_message)
  end
end

private

def configuration
  @configuration ||= begin
    config = PostgresqlBackup.configuration.dup
    config.repository = ENV['BKP_REPOSITORY'] if ENV['BKP_REPOSITORY'].present?
    config.bucket = ENV['BKP_BUCKET'] if ENV['BKP_BUCKET'].present?
    config.region = ENV['BKP_REGION'] if ENV['BKP_REGION'].present?
    config.remote_path = ENV['BKP_REMOTE_PATH'] if ENV['BKP_REMOTE_PATH'].present?
    config
  end
end

def db
  @db ||= Tools::Database.new(configuration)
end

def storage
  @storage ||= Tools::S3Storage.new(configuration)
end

def disclaimer
  @disclaimer ||= Tools::Disclaimer.new
end

def pastel
  @pastel ||= Pastel.new
end

def prompt
  @prompt ||= TTY::Prompt.new
end

def configuration_to_text
  [
    show_config_for('Repository', configuration.repository),
    configuration.s3? ? nil : show_config_for('Folder', configuration.backup_folder),
    show_config_for('File suffix', configuration.file_suffix),
    configuration.s3? ? show_config_for('Bucket', configuration.bucket) : nil,
    configuration.s3? ? show_config_for('Region', configuration.region) : nil,
    configuration.s3? ? show_config_for('Remote path', configuration.remote_path) : nil
  ].compact
end

def show_config_for(text, value)
  return if value.empty?

  "* #{pastel.yellow.bold(text)}: #{value}"
end

def list_backup_files
  @list_backup_files ||= begin
    source = configuration.s3? ? storage : db
    source.list_files
  end
end

end