require 'rails_helper'

describe WebRequestsController do
  class Agents::WebRequestReceiverAgent < Agent
    cannot_receive_messages!
    cannot_be_scheduled!

    def receive_web_request(params, method, format)
      if params.delete(:secret) == options[:secret]
        memory[:web_request_values] = params
        memory[:web_request_format] = format
        memory[:web_request_method] = method
        ['success', (options[:status] || 200).to_i, memory['content_type'], memory['response_headers']]
      else
        ['failure', 404]
      end
    end
  end

  before do
    stub(Agents::WebRequestReceiverAgent).valid_type?('Agents::WebRequestReceiverAgent') { true }
    @agent = Agents::WebRequestReceiverAgent.new(name: 'something', options: { secret: 'my_secret' })
    @agent.user = users(:bob)
    @agent.save!
  end

  it 'should not require login to receive a web request' do
    expect(@agent.last_web_request_at).to be_nil
    post :handle_request, params: { user_id: users(:bob).to_param, agent_id: @agent.id, secret: 'my_secret', key: 'value', another_key: '5' }
    expect(@agent.reload.last_web_request_at).to be_within(2).of(Time.now)
    expect(response.body).to eq('success')
    expect(response).to be_successful
  end

  it 'should call receive_web_request' do
    post :handle_request, params: { user_id: users(:bob).to_param, agent_id: @agent.id, secret: 'my_secret', key: 'value', another_key: '5' }
    @agent.reload
    expect(@agent.memory[:web_request_values]).to eq({ 'key' => 'value', 'another_key' => '5' })
    expect(@agent.memory[:web_request_format]).to eq('text/html')
    expect(@agent.memory[:web_request_method]).to eq('post')
    expect(response.body).to eq('success')
    expect(response.headers['Content-Type']).to eq('text/plain; charset=utf-8')
    expect(response).to be_successful

    post :handle_request, params: { user_id: users(:bob).to_param, agent_id: @agent.id, secret: 'not_my_secret', no: 'go' }
    expect(@agent.reload.memory[:web_request_values]).not_to eq({ 'no' => 'go' })
    expect(response.body).to eq('failure')
    expect(response).to be_not_found
  end

  it 'should accept gets' do
    get :handle_request, params: { user_id: users(:bob).to_param, agent_id: @agent.id, secret: 'my_secret', key: 'value', another_key: '5' }
    @agent.reload
    expect(@agent.memory[:web_request_values]).to eq({ 'key' => 'value', 'another_key' => '5' })
    expect(@agent.memory[:web_request_format]).to eq('text/html')
    expect(@agent.memory[:web_request_method]).to eq('get')
    expect(response.body).to eq('success')
    expect(response).to be_successful
  end

  it 'should pass through the received format' do
    get :handle_request, params: { user_id: users(:bob).to_param, agent_id: @agent.id, secret: 'my_secret', key: 'value', another_key: '5' }, format: :json
    @agent.reload
    expect(@agent.memory[:web_request_values]).to eq({ 'key' => 'value', 'another_key' => '5' })
    expect(@agent.memory[:web_request_format]).to eq('application/json')
    expect(@agent.memory[:web_request_method]).to eq('get')

    post :handle_request, params: { user_id: users(:bob).to_param, agent_id: @agent.id, secret: 'my_secret', key: 'value', another_key: '5' }, format: :xml
    @agent.reload
    expect(@agent.memory[:web_request_values]).to eq({ 'key' => 'value', 'another_key' => '5' })
    expect(@agent.memory[:web_request_format]).to eq('application/xml')
    expect(@agent.memory[:web_request_method]).to eq('post')

    put :handle_request, params: { user_id: users(:bob).to_param, agent_id: @agent.id, secret: 'my_secret', key: 'value', another_key: '5' }, format: :atom
    @agent.reload
    expect(@agent.memory[:web_request_values]).to eq({ 'key' => 'value', 'another_key' => '5' })
    expect(@agent.memory[:web_request_format]).to eq('application/atom+xml')
    expect(@agent.memory[:web_request_method]).to eq('put')
  end

  it 'can accept a content-type to return' do
    @agent.memory['content_type'] = 'application/json'
    @agent.save!
    get :handle_request, params: { user_id: users(:bob).to_param, agent_id: @agent.id, secret: 'my_secret', key: 'value', another_key: '5' }
    expect(response.headers['Content-Type']).to eq('application/json; charset=utf-8')
  end

  it 'can accept custom response headers to return' do
    @agent.memory['response_headers'] = { 'Access-Control-Allow-Origin' => '*' }
    @agent.save!
    get :handle_request, params: { user_id: users(:bob).to_param, agent_id: @agent.id, secret: 'my_secret', key: 'value', another_key: '5' }
    expect(response.headers['Access-Control-Allow-Origin']).to eq('*')
  end

  it 'can accept multiple custom response headers to return' do
    @agent.memory['response_headers'] = { 'Access-Control-Allow-Origin' => '*', 'X-My-Custom-Header' => 'hello' }
    @agent.save!
    get :handle_request, params: { user_id: users(:bob).to_param, agent_id: @agent.id, secret: 'my_secret', key: 'value', another_key: '5' }
    expect(response.headers['Access-Control-Allow-Origin']).to eq('*')
    expect(response.headers['X-My-Custom-Header']).to eq('hello')
  end

  it 'should redirect correctly' do
    @agent.options['status'] = 302
    @agent.save
    post :handle_request, params: { user_id: users(:bob).to_param, agent_id: @agent.id, secret: 'my_secret' }, format: :json
    expect(response).to redirect_to('success')
  end

  it 'should fail on incorrect users' do
    post :handle_request, params: { user_id: users(:jane).to_param, agent_id: @agent.id, secret: 'my_secret', no: 'go' }
    expect(response).to be_not_found
  end

  it 'should fail on incorrect agents' do
    post :handle_request, params: { user_id: users(:bob).to_param, agent_id: 454_545, secret: 'my_secret', no: 'go' }
    expect(response).to be_not_found
  end
end
