namespace :shopapp do

def deployment_settings
  target = ENV['target'] || 'production'
  Rails.configuration.settings['deployment']['default'].to_h.merge(
    Rails.configuration.settings['deployment'][target].to_h
  )
end

def deployment_targets
  Rails.configuration.settings['deployment'].to_h.keys - ['default']
end

def fetchdb(timestamp)
  user = deployment_settings['dbuser'] || deployment_settings['user']
  server = deployment_settings['dbserver'] || deployment_settings['server']
  db_name = deployment_settings['dbname'] || Rails.configuration.database_configuration['production']['database']
  dump_filename = "#{db_name}_#{timestamp}.dump"

  puts "Creating production db backup from #{db_name} to #{dump_filename}..."
  host_flag = if deployment_settings['dbhost'].present?
    "-h #{deployment_settings['dbhost']}"
  end
  system "ssh #{user}@#{server} 'pg_dump -Fc -c --no-owner #{host_flag} #{db_name} > #{dump_filename}'"
  mkdir_p Rails.root.join('tmp')
  puts "Copying to local..."
  system "scp #{user}@#{server}:#{dump_filename} #{Rails.root.join('tmp')}"
end

def restoredb(timestamp)
  db_name = deployment_settings['dbname'] || Rails.configuration.database_configuration['production']['database']
  dump_filename = "#{db_name}_#{timestamp}.dump"
  restoredb_from_file(dump_filename)
end

def restoredb_from_file(dump_filepath)
  dev_db_name = Rails.configuration.database_configuration['development']['database']
  puts "Restoring to local development database from #{dump_filepath}..."
  system "pg_restore --no-owner --verbose -c --no-acl -n public --dbname #{dev_db_name} #{Rails.root.join('tmp', dump_filepath)}"
  puts "Done restoring the database from #{dump_filepath} to local development."
end

desc 'list existing targets'
task targets: :environment do
  puts deployment_targets.join(', ')
end

desc 'pull prod db to local dev'
task pulldb: :environment do
  timestamp = Time.now.strftime('%Y%m%d%H%M%S')
  fetchdb(timestamp)
  restoredb(timestamp)
end

desc 'fetch prod db to local tmp folder'
task fetchdb: :environment do
  timestamp = Time.now.strftime('%Y%m%d%H%M%S')
  fetchdb(timestamp)
end

desc 'execute command on production server'
task run: :environment do
  ARGV.each { |a| task a.to_sym do ; end }
  user = deployment_settings['user']
  server = deployment_settings['server']

  deployment_folder_name = (deployment_settings['folder']) ||
                           "#{(Rails.configuration.settings['shopapp_name'] ||
                            Rails.application.class.parent_name).to_s.downcase.parameterize.underscore}/current"

  cmd = %(ssh -t #{user}@#{server} 'cd #{deployment_folder_name}; bash --login -c "#{ARGV[1..-1].join(' ')}"')
  exec cmd
end

desc "tails and follows target's log/production.log"
task :tail do
  exec %(target=#{ENV['target']} rake shopapp:run "tail -f log/production.log")
end

desc "opens bash prompt on target"
task :bash do
  exec %(target=#{ENV['target']} rake shopapp:run "/bin/bash")
end

desc "opens rails console on target"
task :console do
  exec %(target=#{ENV['target']} rake shopapp:run "rails c")
end

desc "executes rake task(s) on target"
task rake: :environment do
  exec %(target=#{ENV['target']} rake shopapp:run "rake #{ARGV[1]}")
end

desc "list revisions (including last one)"
task revs: :environment do
  ARGV.each { |a| task a.to_sym do ; end }
  user = deployment_settings['user']
  server = deployment_settings['server']

  deployment_folder_name = (deployment_settings['folder']) ||
                           "#{(Rails.configuration.settings['shopapp_name'] ||
                            Rails.application.class.parent_name).to_s.downcase.parameterize.underscore}/current"

  cmd = %(ssh -t #{user}@#{server} 'cd #{deployment_folder_name.gsub('/current', '')}; ls ; cat revisions.log')
  exec cmd
end

desc 'help about these rakes tasks'
task :help do
  puts case ENV['cmd']
        when 'console'
          'Opens rails console on the target. No parameters allowed.'
        when 'tail'
          'Tails main production log on target, until CTRL+C. No parameters allowed.'
        when 'bash'
          'Opens the bash terminal on target with application user in the deployment folder. No parameters allowed.'
        when 'run'
          'Executes on target in deployment directory under deployment user arbitrary command specified by parameters.'
        when 'rake'
          "Executes a rake task on target in deployment directory under deployment user.\n" +
          "First parameter is task name (possiblly with namespace(s)), other parameters are passed to rake task."
        when 'pulldb'
          'Dumps target production database and restores it to local development db. No parameters allowed.'
        when 'fetchdb'
          'Dumps target production database and copies it to local tmp folder.'
        when 'restoredb'
          "Restores database dump fetched with fetchdb from tmp folder.\n" +
          "Parameter is the database name without dump suffix). Default is the latest dump."
        when 'revs'
          "Shows latest deployed revisions. Last one (lowest one) is the active one."
        when 'help'
          "Com'on, for real!"
        else
          "There is no command #{ENV['cmd']}"
        end
end

task restoredb: :environment do
  dump_filepath ||= if ENV['timestamp']
                      Rails.root.join "tmp/#{deployment_settings['dbname']}_#{ENV['timestamp']}.dump"
                    else
                      ENV['filepath'] ||
                        Dir[Rails.root.join("tmp/#{deployment_settings['dbname']}_*.dump")].sort.last
                    end
  restoredb_from_file(dump_filepath)
end

end