namespace :psql_backups do

class String
  def black;          "\e[30m#{self}\e[0m" end
  def red;            "\e[31m#{self}\e[0m" end
  def green;          "\e[32m#{self}\e[0m" end
  def brown;          "\e[33m#{self}\e[0m" end
  def blue;           "\e[34m#{self}\e[0m" end
  def magenta;        "\e[35m#{self}\e[0m" end
  def cyan;           "\e[36m#{self}\e[0m" end
  def gray;           "\e[37m#{self}\e[0m" end
  def dark_gray;      "\e[1:30m#{self}\e[0m" end
  def white;          "\e[1;37m#{self}\e[0m" end

  def bg_black;       "\e[40m#{self}\e[0m" end
  def bg_red;         "\e[41m#{self}\e[0m" end
  def bg_green;       "\e[42m#{self}\e[0m" end
  def bg_brown;       "\e[43m#{self}\e[0m" end
  def bg_blue;        "\e[44m#{self}\e[0m" end
  def bg_magenta;     "\e[45m#{self}\e[0m" end
  def bg_cyan;        "\e[46m#{self}\e[0m" end
  def bg_gray;        "\e[47m#{self}\e[0m" end

  def bold;           "\e[1m#{self}\e[22m" end
  def italic;         "\e[3m#{self}\e[23m" end
  def underline;      "\e[4m#{self}\e[24m" end
  def blink;          "\e[5m#{self}\e[25m" end
  def reverse_color;  "\e[7m#{self}\e[27m" end
end

desc "Backup database"
task :backup, [:tag] => [:environment] do |t, args|
  raise "Can only be run in development environment" unless Rails.env.development?
  raise "Can only be run if configured for local database" unless ActiveRecord::Base.connection.raw_connection.conninfo_hash[:host].nil?
  raise "Invalid tag. Tags have to purely alphanumeric (no special characters)" unless args[:tag].nil? || /^[a-z0-9]+$/.match?(args[:tag])
              dbname = ActiveRecord::Base.connection.raw_connection.conninfo_hash[:dbname]
  backup_dbname = "#{ dbname }_#{ args[:tag] || Time.current.strftime("%Y%m%d%H%M%S") }"
  ActiveRecord::Base.connection.disconnect!
  `psql -c "alter database #{ dbname } rename to #{ backup_dbname };"`
  `psql -c "create database #{ dbname } template #{ backup_dbname };"`
end

desc "Show backups"
task list: :environment do
  raise "Can only be run in development environment" unless Rails.env.development?
  raise "Can only be run if configured for local database" unless ActiveRecord::Base.connection.raw_connection.conninfo_hash[:host].nil?
              dbname = ActiveRecord::Base.connection.raw_connection.conninfo_hash[:dbname]
  lines = `psql -c "\\l" | grep #{ dbname }_`.split("\n")
  dbnames = lines.map{|l| l.split('|').first.strip }
  puts "Found #{dbnames.count} backup(s):"
  dbnames.each do |d|
    print "[#{dbname}_]".gray.italic
    puts d.sub("#{dbname}_", "").white
  end
end

desc "Restore from backup"
task :restore, [:tag] => [:environment] do |t, args|
  raise "Can only be run in development environment" unless Rails.env.development?
  raise "Can only be run if configured for local database" unless ActiveRecord::Base.connection.raw_connection.conninfo_hash[:host].nil?
  raise "No tag specified" if args[:tag].nil?

              dbname = ActiveRecord::Base.connection.raw_connection.conninfo_hash[:dbname]
  lines = `psql -c "\\l" | grep #{ dbname }_`.split("\n")
  tags = lines.map{|l| l.split('|').first.strip.sub("#{dbname}_", '') }

  raise "Tag not found in backups" unless tags.include?(args[:tag])

  puts "Your existing database will be replaced. Are you sure you want to continue? [y/N]"
  input = STDIN.gets.chomp
  raise "User abort" unless input.downcase == "y"

  restore_dbname = "#{ dbname }_#{ args[:tag] }"
  backup_dbname = "#{ dbname }_auto_#{ Time.current.strftime("%Y%m%d%H%M%S") }"
  ActiveRecord::Base.connection.disconnect!
  `psql -c "alter database #{ dbname } rename to #{ backup_dbname };"`
  `psql -c "create database #{ dbname } template #{ restore_dbname };"`
end

desc "Clear auto backups"
task clear: :environment do
  raise "Can only be run in development environment" unless Rails.env.development?
  raise "Can only be run if configured for local database" unless ActiveRecord::Base.connection.raw_connection.conninfo_hash[:host].nil?

  puts "All your auto-backups will be cleared. Are you sure you want to continue? [y/N]"
  input = STDIN.gets.chomp
  raise "User abort" unless input.downcase == "y"

              dbname = ActiveRecord::Base.connection.raw_connection.conninfo_hash[:dbname]
  lines = `psql -c "\\l" | grep #{ dbname }_auto_`.split("\n")
  backups = lines.map{|l| l.split('|').first.strip}

  ActiveRecord::Base.connection.disconnect!
  backups.each do |backup_dbname|
    `psql -c "drop database #{backup_dbname};"`
  end
end

end