if RUBY_PLATFORM != 'opal'
  require 'volt/controllers/http_controller'
  require 'volt/server/rack/http_request'
  require 'volt/server/rack/http_resource'

  describe Volt::HttpController do
    class TestHttpController < Volt::HttpController
      attr_reader :action_called

      def just_call_an_action
        @action_called = true
      end

      def ok_head_action
        head :ok, location: 'http://example.com'
      end

      def created_head_action
        head :created
      end

      def head_with_http_headers
        head :ok, location: 'http://path.to/example'
      end

      def redirect_action
        redirect_to 'http://path.to/example'
      end

      def render_plain_text
        render text: 'just plain text'
      end

      def render_json
        render json: { 'this' => 'is_json', 'another' => 'pair' }
      end

      def render_json_with_custom_headers
        render json: { some: 'json' },
               status: :created, location: '/test/location'
      end

      def access_body
        render json: JSON.parse(request.body.read)
      end
    end

    let(:app) { ->(env) { [404, env, 'app'] } }

    let(:request) do
      Volt::HttpRequest.new(
        Rack::MockRequest.env_for('http://example.com/test.html',
                                  'CONTENT_TYPE' => 'text/plain;charset=utf-8'))
    end

    let(:controller) { TestHttpController.new({}, request) }

    it 'should merge the request params and the url params' do
      request = Volt::HttpRequest.new(
        Rack::MockRequest.env_for('http://example.com/test.html?this=is_a&test=param'))
      controller = TestHttpController.new(
        { another: 'params', 'and_a' => 'string' }, request)
      expect(controller.params.size).to eq(4)
      expect(controller.params._and_a).to eq('string')
      expect(controller.params._this).to eq('is_a')
    end

    it 'should perform the correct action' do
      expect(controller.action_called).not_to be(true)
      controller.perform(:just_call_an_action)
      expect(controller.action_called).to be(true)
    end

    it 'should redirect' do
      expect(controller.action_called).not_to be(true)
      response = controller.perform(:redirect_action)
      expect(response.location).to eq('http://path.to/example')
      expect(response.status).to eq(302)
    end

    it 'should respond with head' do
      response = controller.perform(:ok_head_action)
      expect(response.status).to eq(200)
      expect(response.body).to eq([])

      response = controller.perform(:created_head_action)
      expect(response.status).to eq(201)

      response = controller.perform(:head_with_http_headers)
      expect(response.headers['Location']).to eq('http://path.to/example')
      expect(response.location).to eq('http://path.to/example')
    end

    it 'should render plain text' do
      response = controller.perform(:render_plain_text)
      expect(response.status).to eq(200)
      expect(response['Content-Type']).to eq('text/plain')
      expect(response.body).to eq(['just plain text'])
    end

    it 'should render json' do
      response = controller.perform(:render_json)
      expect(response.status).to eq(200)
      expect(response['Content-Type']).to eq('application/json')
      expect(JSON.parse(response.body.first)).to eq('this' => 'is_json',
                                                    'another' => 'pair')
    end

    it 'should set the correct status for rendered responses' do
      response = controller.perform(:render_json_with_custom_headers)
      expect(response.status).to eq(201)
    end

    it 'should include the custum headers' do
      response = controller.perform(:render_json_with_custom_headers)
      expect(response['Location']).to eq('/test/location')
    end

    it 'should have access to the body' do
      http_app = Volt::HttpResource.new(app, nil)
      allow(http_app).to receive(:routes_match?)
        .and_return(controller: 'test_http',
                    action: 'access_body')
      request = Rack::MockRequest.new(http_app)
      response = request.post('http://example.com/test.html', input:
        { test: 'params' }.to_json)
      expect(response.body).to eq({ test: 'params' }.to_json)
    end
  end
end