require 'phrase/tool_config'

require 'optparse'
require 'net/http'
require 'net/https'
require 'fileutils'

module PhraseGem
  class Tool

    def initialize(argv)
      @args = argv
    end

    def run
      config = ToolConfig.new
      command = args.first

      case command
        when /init/
          init(config)
        when /push/
          push(config)
        when /pull/
          pull(config)
        else
          print_usage
      end
    end

    private
    def init(config)
      secret_param = args.find{ |arg| arg =~ /secret=/ }
      unless secret_param.to_s.match(/secret=.+/)
        $stderr.puts "Need a secret to init, but found none."
        $stderr.puts "Please provide the --secret=YOUR_SECRET parameter."
        exit(41)
      end

      secret = secret_param.split("=", 2).last
      config.secret = secret
      puts "Wrote secret to config file .phrase"
    end

    def push(config)
      files = choose_files_to_upload
      if files.empty?
        puts "Could not find any files to upload :("
        exit(43)
      end
      
      if !config.secret || config.secret.empty?
        puts "No config present. Please initialize phrase before pushing or pulling."
        exit(43)
      end
      
      files.each do |file|
        if file.split('.').last != 'yml'
          $stderr.puts "Currently only .yml files are supported."
          exit(43)
        end
      end
      
      upload_files(files, config)
    end

    def choose_files_to_upload
      file_name = args[1]
      unless file_name
        $stderr.puts "Need either a file or directory:"
        $stderr.puts " phrase push FILE"
        $stderr.puts " phrase push DIRECTORY"
        exit(46)
      end

      unless File.exist?(file_name)
        $stderr.puts "The file #{file_name} could not be found."
        exit(42)
      end

      if File.directory?(file_name)
        files = Dir.glob("#{File.expand_path(file_name)}/**")
      else
        files = [file_name]
      end
    end

    def upload_files(files, config)
      files.each do |file|
        puts "Uploading #{file}..."
        params = {
          'auth_token'=>config.secret,
          'filename'=> file,
          'file_content' => File.read(file)
        }
        
        http = http_client(config)
        
        request = Net::HTTP::Post.new("#{config.api_path_prefix}/translation_keys/upload")
        request.set_form_data(params)
        res = http.request(request)

        dump_summary_to_file(res, file)
        unless res.code.to_s =~ /^[23]/
          print_server_error(res, file)
        end
      end
    end

    def pull(config)
      locale = args[1]
      print "Downloading phrase.#{locale}.yml..."
      ::FileUtils.mkdir_p("phrase/locales")
      
      http = http_client(config)
      
      request = Net::HTTP::Get.new("#{config.api_path_prefix}/translations/download?auth_token=#{config.secret}&locale=#{locale}")
      res = http.request(request)
      
      if res.code.to_s =~ /200/
        puts " OK"
        File.open("phrase/locales/phrase.#{locale}.yml", "w") do |file|
          file.write(res.body)
        end
      else
        puts " Failed"
        print_server_error(res)
      end
    end

    def print_server_error(res, filename=nil)
      error_message = server_error_message(res.body)
      $stderr.puts "Server error: #{res.code} - #{error_message} (#{filename})"
    end

    def server_error_message(body)
      begin
        JSON.parse(body)["error"]
      rescue JSON::ParserError
        "Unkown error"
      end
    end

    def print_usage
      $stderr.puts <<USAGE
Welcome to phrase!
    phrase           Prints usage

    phrase init --secret=<YOUR SECRET>

    phrase push FILE
    phrase push DIRECTORY
USAGE
    end

    def args
      @args
    end

    def puts_debug_info
      puts "ARGS: #{args.join(",")}"
      puts "Dir.pwd: #{Dir.pwd}"
    end
    
    def dump_summary_to_file(res, upload_file)
      ::FileUtils.mkdir_p("phrase/uploads/")
      timestamp = Time.now.strftime("%Y%m%m-%H%M%S")
      file_name = "#{File.basename(upload_file)}-#{timestamp}"
      summary_file = "phrase/uploads/#{file_name}.json"
      File.open(summary_file, "w") do |file|
        file.write(res.body)
      end
      puts "Summary saved in #{summary_file}"
    end
    
    def http_client(config)
      http = Net::HTTP.new(config.api_host, config.api_port)
      http.use_ssl = true if config.api_use_ssl == "1"
      http.verify_mode = OpenSSL::SSL::VERIFY_NONE
      http.ca_file = File.join(File.dirname(__FILE__), "..", "..", "cacert.pem")
      http
    end
  end
end