require "sinatra/base"
require "sinatra/streaming"
require "json"

require "fog"

require "exceptions/invalid_privileges"
require "exceptions/invalid_record"
require "exceptions/configuration_error"
require "exceptions/record_not_found"
require "exceptions/dependency_error"
require "exceptions/conflict_exception"
require "exceptions/parser_error"
require "exceptions/validation_error"
require "exceptions/knife_config_error"
require "exceptions/access_error"
require 'core/devops-logger'

require_relative "../helpers/query"

require 'swagger/blocks'

module Devops
  class Api3 < Sinatra::Base

    include Swagger::Blocks

    include Sinatra::JSON
    helpers Sinatra::Streaming
    helpers Devops::API3::Helpers

    register Sinatra::DevopsAuth

    @@logger = nil
    @@access_logger = DevopsLogger.access_logger(File.join(DevopsConfig.config[:log_dir], "devops-api3.access.log"))

    set :root, File.expand_path("../../", __FILE__)
    set :public_folder, Proc.new { File.join(root, "public") }

    configure :production do
      config = DevopsConfig.config
      log_file = File.join(config[:log_dir], "devops-api3.log")
      @@logger = DevopsLogger.create(log_file, Logger::INFO)
      disable :dump_errors
      disable :show_exceptions
      #set :logging, Logger::INFO
      @@logger.info "Production mode"
    end

    configure :development do
      config = DevopsConfig.config
      log_file = File.join(config[:log_dir], "devops-api3.dev.log")
      @@logger = DevopsLogger.create(log_file, Logger::DEBUG)
      disable :raise_errors
      set :show_exceptions, false
      disable :show_exceptions
      enable :logging
      use Rack::CommonLogger, @@logger
      @@logger.info "Development mode"
      puts root
      puts public_folder
    end

    def logger
      @@logger
    end

    error Sinatra::NotFound do
      content_type 'text/plain'
      [404, "#{request.url} not found"]
    end

    # set current logger and call handlers
    def call env
      DevopsLogger.logger = @@logger
      res = super(env)
      @@access_logger.info(env["REQUEST_METHOD"] + " " + env["REQUEST_URI"] + " - from #{env["HTTP_USER_AGENT"]} (#{env["REMOTE_USER"]}) / #{res[0]}") if env["REMOTE_USER"]
      res
    end

    def handle_exception!(boom)
      if boom.is_a?(::Devops::Exception::DevopsError)
        boom.http_response
      elsif boom.is_a?(Mongoid::Errors::Validations)
        Devops::Exception::ValidationError.create_from_db_exception(boom).http_response
      elsif boom.is_a?(Mongoid::Errors::InvalidValue)
        Devops::Exception::ParserError.create_from_db_exception(boom).http_response
      elsif boom.is_a?(Sinatra::NotFound)
        super(boom)
      else
        @@logger.error boom.message + "\n\t" + boom.backtrace.join("\n\t")
        super(boom)
      end
    end

    error Devops::Exception::KnifeConfigError do
      e = env["sinatra.error"]
      logger.error e.message
      halt_response(e.message, 500)
    end

    error Excon::Errors::Error do
      e = env["sinatra.error"]
      logger.warn e.message
      halt_response(e.message, 400)
    end

    error ::Excon::Errors::Unauthorized do
      e = env["sinatra.error"]
      resp = e.response
      ct = resp.headers["Content-Type"]
      msg = unless ct.nil?
        if ct.include?("application/json")
          json = ::Chef::JSONCompat.from_json(resp.body)
          m = "ERROR: Unauthorized (#{json['error']['code']}): #{json['error']['message']}"
          logger.error(m)
        else
        end
        m
      else
        "Unauthorized: #{e.inspect}"
      end
      halt_response(msg, 500)
    end

    error Fog::Compute::AWS::Error do
      e = env["sinatra.error"]
      logger.error e.message
      halt_response(e.message, 500)
    end

    error do
      e = env["sinatra.error"]
      logger.error e.message
      halt_response(e.message, 500)
    end

  end
end
