Buildwise::App.controllers :api do
  
  get "/builds/:id/load-test-result" do   
    content_type :json
     
    @build = Build.find(params[:id])
    raw_data = LoadTestResult.where(:build_id => @build.id)    

    data_timestamp = params[:data_timestamp]
    if (data_timestamp && data_timestamp.to_i > 0)
      raw_data = raw_data.where("start_timestamp > ?", data_timestamp)
    end
    
    @data = []
    raw_data.each do |rd|      
      start_hash = {id: rd.id,  x: rd.start_timestamp, y: 0}
      data_hash = {id: rd.id, x: (rd.start_timestamp + rd.end_timestamp) / 2, y: rd.duration}
      end_hash = { id: rd.id, x: rd.end_timestamp, y: 0}
      
      if @build.incomplete?
        start_hash[:op] = rd.operation  
        data_hash[:op] = rd.operation  
        end_hash[:op] = rd.operation  
      end
      
      @data << start_hash
      @data << data_hash
      @data << end_hash
    end
    return @data.to_json
  end
  


  get "/projects/:id/status" do
    content_type :json

    @project = find_project(params[:id])
    recent_five_builds = @project.builds.last(5)
    buildwise_master_host = @project.config.environment_variables["BUILDWISE_MASTER"] || root_url

    build_summary_list = []
    recent_five_builds.each do |b|
      next if b.incomplete?

      status_text = ""
      if b.ui_test_error_count > 0
        status_text = "Tests failed: #{b.ui_test_error_count}, passed: #{b.ui_test_count - b.ui_test_error_count}"
      else
        status_text = "Tests passed: #{b.ui_test_count - b.ui_test_error_count}"
      end

      build_duration = b.duration.round(1) rescue 0
      test_execution_time = b.test_execution_time.round(1) rescue 0

      hash = {
          "projectName" => @project.name,
          "buildTypeId" => @project.identifier,
          "startDate" => b.start_time.localtime.iso8601,
          "finishDate" => b.finish_time ? b.finish_time.localtime.iso8601 : b.start_time.localtime.iso8601,
          "buildTime" => build_duration,
          "is_parallel" => b.is_parallel,
          "agentsCount" => b.is_parallel ? b.build_agents.size : 1,
          "testExecutionTime" => test_execution_time,
          "webUrl" => "#{buildwise_master_host}/builds/#{b.id}",
          "status" => b.successful ? "SUCCESS" : "FAILURE",
          "totalTests" => b.ui_test_count,
          "failedTests" => b.ui_test_error_count,
          "statusText" => status_text,
          "summary" => b.summary
      }

      if b.summary && b.summary.size > 1
        hash["statusText"] += "; " + b.summary
      end
      build_summary_list << hash
    end

    project_status_summary = {
        :count => @project.builds.count,
        :build => build_summary_list.reverse
    }

    return project_status_summary.to_json
  end



  get "/wemo_switch_status" do
    ip_address = params[:ip].to_s
    unless ip_address =~ /^http/
      ip_address = "http://#{ip_address}:49153/"
    end

    @switch_status = nil

    require 'net/http'
    require 'uri'
    uri = URI.parse(ip_address.to_s + 'upnp/control/basicevent1')
    http = Net::HTTP.new(uri.host, uri.port)
    header = {}
    header["Content-type"] = 'text/xml; charset="utf-8"'
    header["SOAPACTION"] = "\"urn:Belkin:service:basicevent:1#GetBinaryState\""
    req = Net::HTTP::Post.new(uri.request_uri, header)
    begin
      req.body = "<?xml version='1.0' encoding='utf-8'?><s:Envelope xmlns:s='http://schemas.xmlsoap.org/soap/envelope/' s:encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'><s:Body><u:GetBinaryState xmlns:u='urn:Belkin:service:basicevent:1'></u:GetBinaryState></s:Body></s:Envelope>"
      the_response = http.request(req)
      response_body = the_response.body

      if response_body.include?("<BinaryState>0</BinaryState>")
        @switch_status = "off"
      elsif response_body.include?("<BinaryState>1</BinaryState>")
        @switch_status = "on"
      else
        @switch_status = nil
      end

    rescue => e
      @switch_status = nil
      logger.warn("I can't access the wemo at #{ip_address} now, error => #{e}")
    end
    return @switch_status
  end
  
  
  
  get "/tplink_smart_plug_status" do
    device_name = params[:device_name].to_s
    @switch_status = nil    
    begin
      require 'tp_link'
      kasa_user = ENV["TP_LINK_CLOUD_ACCOUNT_USER"]
      sh = TPLink::SmartHome.new('user' => kasa_user,'password' => ENV["TP_LINK_CLOUD_ACCOUNT_PASS"])
      plug = sh.find(device_name)
      if plug && plug.on?
        @switch_status = "on"
      elsif plug && plug.off? 
        @switch_status = "off"
      end
    rescue =>  e
      puts("failed!!!: #{e}")
      logger.warn("Failed to get tplink smart plug status: #{e}")
    end

    return @switch_status
  end
  
  



  


  post "/projects" do
    content_type :json    
    result = {}
    
    if !is_authenticated_for_server?(params[:api_key])
      result[:status] = "Failed"
      result[:message] = "Not authorized."
      return result.to_json   
    end

    if params.keys.size == 1

      request.body.rewind
      new_project_hash = ActiveSupport::JSON.decode(request.body.read)
    else
      new_project_hash = params.dup
    end
  
    return create_project(new_project_hash)
  end
  


  post "/projects/:id/trigger_build" do
    content_type :json

    @project = find_project(params[:id])
    result = {}

    if @project.nil?
      result[:status] = "Failed"
      result[:message] = "Project '#{params[:id]}' not exists"
      return result.to_json          
    end    
        
    if is_authenticated_for_project?(@project, params[:api_key])
      logger.info("Force a build from API: #{BuildRunner.busy?}")
      if !BuildRunner.busy?
        next_project_build = BuildRunner.force_build(@project)
        if next_project_build

          next_project_build.update_column(:triggered_by_user_id, 0)
        end
        result[:status] = "OK"
        result[:build_id] = next_project_build.id
        BuildRunner.build_now(next_project_build)
        @autorefresh = true
        logger.info("next project build: #{next_project_build}")
      else
        result[:status] = "Failed"
        result[:message] = "The server is busy building another project."        
      end
      
    else      
        result[:status] = "Failed"
        result[:message] = "Not authorized."
    end
    
    return result.to_json    
  end

  get "/projects/:id/config" do
    content_type :json

    @project = find_project(params[:id])
    result = {}

    if @project.nil?
      result[:status] = "Failed"
      result[:message] = "Project '#{params[:id]}' not exists"
      return result.to_json          
    end    
        
    if is_authenticated_for_project?(@project, params[:api_key]) || RACK_ENV=="local"
      result[:status] = "OK"
      result[:config] = @project.config_file_content
    else      
        result[:status] = "Failed"
        result[:message] = "Not authorized."
    end
    
    return result.to_json    
  end
  
  get "/builds/:id/result" do
    content_type :json
    result = {}
    @build = Build.find_by_id(params[:id])    
    if @build.nil?
      result[:status] = "Failed"
      result[:message] = "Build '#{params[:id]}' not exists"
      return result.to_json          
    end    
    project = @build.project rescue nil

    if is_authenticated_for_project?(project, params[:api_key])
      result[:status] = "OK"
      if @build.status == "complete"
        result[:successful] = @build.successful ? "true" : "false"
      else
        result[:successful] = "pending"
      end
    else      
      result[:status] = "Failed"
      result[:message] = "Not authorized."
    end  
    return result.to_json    
  end
  
  


  post "/builds/:id/cancel" do
    content_type :json
    result = {}
    @build = Build.where(:id => params[:id]).first
    if @build.nil?
      result[:status] = "Failed"
      result[:message] = "Build '#{params[:id]}' not exists"
      return result.to_json          
    end    
    project = @build.project rescue nil

    if is_authenticated_for_project?(project, params[:api_key])
      @build.cancel
      Buildwise::App.cache.clear    
      result[:status] = "OK"
    else      
      result[:status] = "Failed"
      result[:message] = "Not authorized."
    end  
    return result.to_json    
  end
  


  post "/builds/:id/complete" do
    content_type :json
    result = {}

    @build = Build.where(:id => params[:id]).first
    if @build.nil?
      result[:status] = "Failed"
      result[:message] = "Build '#{params[:id]}' not exists"
      return result.to_json          
    end    

    project = @build.project rescue nil
    if is_authenticated_for_project?(project, params[:api_key])
      
      @build.refresh_ui_test_status
      @build.status = "complete"
      @build.successful = @build.ui_test_status == "OK"
      @build.finish_time = Time.now
      @build.duration = (@build.finish_time - @build.start_time) rescue nil

      if @build.save
        result[:status] = "OK"
      else
        result[:status] = "Failed" 
        result[:message] = @build.errors.full_messages.to_s     
      end

    else
      result[:status] = "Failed"
      result[:message] = "Not authorized."
    end
    
    return result.to_json      
  end
  
  
end