#!/usr/bin/env ruby

require File.expand_path(File.dirname(__FILE__)+ '/../lib/s3_website')
require 'colored'

class Cfg < Thor
  desc 'create', 'Create a config file with placeholder values'
  def create
    config_file_src = File.dirname(__FILE__) + '/../resources/configuration_file_template.yml'
    config_file = Dir.pwd + '/s3_website.yml'
    unless File.exists? config_file
      require 'fileutils'
      FileUtils.cp config_file_src, config_file
      puts "Created the config file s3_website.yml. Go fill it with your settings."
    end
  rescue Exception => error
    puts "#{error.message} (#{error.class})"
    exit 1
  end

  desc 'apply', 'Apply the configuration on the AWS services'
  long_desc <<-LONGDESC
    `s3_website cfg apply` will apply the configuration the S3 bucket.

    In addition, if you CloudFront related settings, this command will apply them on the CloudFront distribution.

    If the S3 bucket does not exist, this command will create it
    and configure it to function as a website.
  LONGDESC
  def apply
    puts 'Applying the configurations in s3_website.yml on the AWS services ...'
    require 'configure-s3-website'
    config_source = ConfigureS3Website::FileConfigSource.new 's3_website.yml'
    ConfigureS3Website::Runner.run({
      :config_source => config_source
    })
  rescue Exception => error
    puts "#{error.message} (#{error.class})"
    exit 1
  end
end

class Cli < Thor
  option(
    :site,
    :type => :string,
    :default => 'infer automatically',
    :desc => "The directory where your website files are. When not defined, s3_website will look for the site in #{S3Website::Paths.site_paths.join(' or ')}."
  )
  option(
    :config_dir,
    :type => :string,
    :default => Dir.pwd,
    :desc => "The directory where your config file is. When not defined, s3_website will look in the current working directory."
  )
  desc 'push', 'Push local files with the S3 website'
  long_desc <<-LONGDESC
    `s3_website push` will upload new and changes files to S3. It will
    also delete from S3 the files that you no longer have locally.
  LONGDESC
  def push
    call_dir = Dir.pwd
    project_root = File.expand_path(File.dirname(__FILE__)+ '/..')
    Dir.chdir(project_root) {
      jar_file = resolve_jar project_root
      # Then run it
      run_s3_website_jar(jar_file, call_dir)
    }
  end

  desc 'cfg SUBCOMMAND ...ARGS', 'Operate on the config file'
  subcommand 'cfg', Cfg
end

def run_s3_website_jar(jar_file, call_dir)
  site_path = File.expand_path(S3Website::Paths.infer_site_path options[:site], call_dir)
  config_dir = File.expand_path options[:config_dir]
  args = "--site=#{site_path} --config-dir=#{config_dir}"
  puts "[debg] Using #{jar_file}"
  if system("java -cp #{jar_file} s3.website.Push #{args}")
    exit 0
  else
    exit 1
  end
end

def resolve_jar(project_root)
  development_jar_path =
    project_root + '/target/scala-2.11/s3_website.jar'
  released_jar_lookup_paths = [
    project_root + "/../s3_website-#{S3Website::VERSION}.jar",
    ENV['TMPDIR'] + "/s3_website-#{S3Website::VERSION}.jar"
  ]
  found_jar = ([development_jar_path] + released_jar_lookup_paths)
  .select { |jar_path|
    File.exists? jar_path
  }
  .first
  jar_file =
    if found_jar
      found_jar
    else
      is_development = File.exists?(project_root + '/.git')
      if is_development
        system "./sbt assembly"
        puts development_jar_path
        development_jar_path
      else
        download_jar(released_jar_lookup_paths)
      end
    end
end

def download_jar(released_jar_lookup_paths)
  tag_name = "v#{S3Website::VERSION}"
  downloaded_jar = released_jar_lookup_paths.select { |jar_path|
    File.writable? File.dirname(jar_path)
  }.first
  unless downloaded_jar
    puts "[error] Neither #{released_jar_lookup_paths.join ' or '} is writable. Cannot download s3_website.jar."
    puts "[error] Set either directory as writable to the current user and try again."
    exit 1
  end
  download_url = "https://github.com/laurilehmijoki/s3_website/releases/download/#{tag_name}/s3_website.jar"
  puts "[info] Downloading #{download_url} into #{downloaded_jar}"
  require 'open-uri'
  open(downloaded_jar, 'wb') do |file|
    file << open(download_url).read
  end
  downloaded_jar
end

Cli.start(ARGV)