#!/usr/bin/env ruby
# encoding: UTF-8
gem 'rails', '~> 4.1.0'

require 'rails/version'
require "thor"
require 'io/console' # for password prompt
require File.expand_path('../../lib/alchemy/version', __FILE__)

class AlchemyInstaller < Thor
  include Thor::Actions

  map "-v" => :version
  map "--version" => :version
  desc "version", "Prints current Alchemy CMS version", hide: true
  def version
    puts Alchemy.version
  end

  desc "new PROJECT", "Creates a new Alchemy CMS project."
  method_option :database, type: :string, aliases: "-d", desc: "Type of database to use for this project. Default sqlite."
  def new(project)
    @application = project.downcase.strip.gsub(/ /, '_')
    say welcome_message, :yellow
    say "Step 1: Creating a Rails #{rails_version} application.", :yellow
    say "Please wait...", :yellow
    system("rails _#{rails_version}_ new #{@application} -m #{alchemy_template} -d #{options[:database]} -JT --quiet") || exit!(1)
    say "Successfully created the Rails application!", :green
    say instructions, :yellow
    if options[:database] == 'mysql' || options[:database] == 'postgresql'
      create_database_yml(options[:database])
    end
    system("#{rake_cmd} alchemy:install from_binary=true") || exit!(1)
    say "\nStep 3: Installing Alchemy User into Rails app", :yellow
    say "Please wait...", :yellow
    system("#{rails_cmd} g alchemy:devise:install") || exit!(1)
    say "Done.", :green
    cleanup
    say "\nSuccessfully installed Alchemy CMS\n", :green
    say further_instructions, :yellow
  rescue
    say "\nError while installing Alchemy CMS!\n#{$!}\n", :red
  end

  private

  def rails_version
    Rails::VERSION::STRING
  end

  def rake_cmd
    "#{bundle_cmd} rake"
  end

  def rails_cmd
    "#{bundle_cmd} rails"
  end

  def bundle_cmd
    "cd #{@application} && bundle exec"
  end

  def alchemy_template
    File.join(File.dirname(__FILE__), '..', 'lib', 'rails', 'templates', 'alchemy.rb')
  end

  def welcome_message
    <<-MSG

------------------------------------------------------------
-=      Welcome to the Alchemy Standalone Installer       =-
------------------------------------------------------------

Bootstraping a new Alchemy CMS #{Alchemy.version} project for you.

MSG
  end

  def instructions
    <<-INSTRUCTIONS

Step 2: Configuration

In order to guide you through the installation process we need you to answer some questions.
INSTRUCTIONS
  end

  def further_instructions
    <<-EOF

Step 5: Further Instructions

Change into your app folder:

  $ cd #{@application}

Start your local Rails server with:

  $ bin/rails server

Open your browser and enter the following URL:

http://localhost:3000/admin

and follow the on screen instructions to complete the installation.

We hope you have fun using Alchemy!
EOF
  end

  def cleanup
    append_file "#{@application}/.gitignore" do
      <<-GITIGNORE

# Ignore Alchemy uploads folder
uploads/*

# Ignore sensitive data
config/database.yml
config/initializers/secret_token.rb
GITIGNORE
    end
    %x[
      cd #{@application}
      mkdir -p ./uploads
      touch ./uploads/.gitkeep
    ]
  end

  def create_database_yml(type)
    case type
    when 'mysql'
      say "- MySQL Database settings", :yellow
      @db_user_name = ask("\nPlease enter your local mysql username (DEFAULT: root):")
      @db_user_name = 'root' if @db_user_name.empty?
      @db_password = ask_password("Please enter the password for #{@db_user_name} (Leave blank for none):")
      local_standard_socket = '/tmp/mysql.sock'
      @db_socket = ask("Please enter your local mysql socket (DEFAULT: #{local_standard_socket}):")
      @db_socket = local_standard_socket if @db_socket.empty?
      file = mysql_yml_file
    when 'postgresql'
      say "- PostgreSQL Database settings", :yellow
      @db_user_name = ask("\nPlease enter the local postgresql user name:")
      @db_password = ask_password("Please enter the password for #{@db_user_name} (Leave blank for none):")
      file = postgres_yml_file
    end
    create_file "./#{@application}/config/database.yml", file, force: true
  end

  def mysql_yml_file
<<-DATABASE
# MySQL.  Versions 4.1 and 5.0 are recommended.
#
# Install the MYSQL driver
#   gem install mysql2
#
# Ensure the MySQL gem is defined in your Gemfile
#   gem 'mysql2'
#
# And be sure to use new-style password hashing:
#   http://dev.mysql.com/doc/refman/5.0/en/old-client.html
development:
  adapter: mysql2
  encoding: utf8
  database: #{@application}_development
  pool: 5
  username: #{@db_user_name}
  password: #{@db_password}
  socket: #{@db_socket}

# Warning: The database defined as "test" will be erased and
# re-generated from your development database when you run "rake".
# Do not set this db to the same as development or production.
test:
  adapter: mysql2
  encoding: utf8
  database: #{@application}_test
  pool: 5
  username: #{@db_user_name}
  password: #{@db_password}
  socket: #{@db_socket}

production:
  adapter: mysql2
  encoding: utf8
  database: #{@application}_production
  pool: 5
  username: #{@db_user_name}
  password: #{@db_password}
  socket: #{@db_socket}
DATABASE
  end

  def postgres_yml_file
<<-DATABASE
# PostgreSQL. Versions 8.2 and up are supported.
#
# Install the pg driver:
#   gem install pg
# On OS X with Homebrew:
#   gem install pg -- --with-pg-config=/usr/local/bin/pg_config
# On OS X with MacPorts:
#   gem install pg -- --with-pg-config=/opt/local/lib/postgresql84/bin/pg_config
# On Windows:
#   gem install pg
#       Choose the win32 build.
#       Install PostgreSQL and put its /bin directory on your path.
#
# Configure Using Gemfile
# gem 'pg'
#
development:
  adapter: postgresql
  encoding: unicode
  database: #{@application}_development
  pool: 5
  username: #{@db_user_name}
  password: #{@db_password}

  # Connect on a TCP socket. Omitted by default since the client uses a
  # domain socket that doesn't need configuration. Windows does not have
  # domain sockets, so uncomment these lines.
  #host: localhost

  # The TCP port the server listens on. Defaults to 5432.
  # If your server runs on a different port number, change accordingly.
  #port: 5432

  # Schema search path. The server defaults to $user,public
  #schema_search_path: myapp,sharedapp,public

  # Minimum log levels, in increasing order:
  #   debug5, debug4, debug3, debug2, debug1,
  #   log, notice, warning, error, fatal, and panic
  # Defaults to warning.
  #min_messages: notice

# Warning: The database defined as "test" will be erased and
# re-generated from your development database when you run "rake".
# Do not set this db to the same as development or production.
test:
  adapter: postgresql
  encoding: unicode
  database: #{@application}_test
  pool: 5
  username: #{@db_user_name}
  password: #{@db_password}

production:
  adapter: postgresql
  encoding: unicode
  database: #{@application}_production
  pool: 5
  username: #{@db_user_name}
  password: #{@db_password}
DATABASE
  end

  def ask_password(message)
    password = $stdin.noecho { ask(message) }
    puts "\n"
    password
  end

end

AlchemyInstaller.start