describe Middleware::ActivityLog do
  let(:test_time) { Time.new(2018, 1, 2, 3) }
  let(:response_time) { 10.0 }
  let(:login_name) { 'my-user' }
  let(:session_id) { 'my-session-id' }
  let(:request) { Rack::MockRequest.new(subject) }
  let(:controller) { double('test-controller') }
  let(:client) { double('Twitch::ActivityLog::Client') }
  subject { described_class.new(app) }

  before(:each) do
    allow(Time).to receive(:now).and_return(
      test_time - 2 * response_time,
      test_time - response_time,
      test_time
    )
    allow(Twitch::ActivityLog::Client).to receive(:new).and_return(client)
  end

  context 'when called with a controller' do
    let(:app) do
      lambda do |env|
        env['action_dispatch.request.parameters'] = {
          'rubykey' => 'ruby-value',
          # we expect the following keys to be filtered
          'authenticity_token' => 'should not log authenticity_token',
          'commit' => 'should not log commit',
          'controller' => 'should not log controller',
          'action' => 'should not log action',
          'utf8' => 'should not log utf8'
        }
        allow(controller).to receive(:request)
          .and_return(ActionDispatch::Request.new(env))
        allow(controller).to receive(:response)
          .and_return(ActionDispatch::Response.new(200, {}, 'OK'))
        allow(controller).to receive(:action_name)
          .and_return('test-action-name')
        env['rack.session'] = { 'login_name' => login_name }
        env['rack.request.cookie_hash'] = {
          '_admin_panel_session_id' => session_id
        }
        env['action_controller.instance'] = controller
        [200, { 'Content-Type' => 'text/plain' }, ['OK']]
      end
    end

    it 'logs information' do
      expect(client).to receive(:put).with(
        http_request_body_size: 4,
        http_response_time: response_time,
        user_id: login_name,
        access_date: test_time,
        http_request_method: 'POST',
        http_request_headers: { 'https' => 'off' },
        http_request_url: 'http://example.org/',
        http_response_headers: {},
        http_response_body_size: 2,
        http_response_status_code: 200,
        rails_controller_method: 'RSpec::Mocks::Double.test-action-name',
        rails_params: {
          'rubykey' => 'ruby-value'
        },
        rails_session_id: session_id
      )
      request.post('/', input: 'data', 'CONTENT_TYPE' => 'text/plain')
    end

    it 'logs with no body' do
      expect(client).to receive(:put).with(
        http_request_body_size: 0,
        http_response_time: response_time,
        user_id: login_name,
        access_date: test_time,
        http_request_method: 'GET',
        http_request_headers: { 'https' => 'off' },
        http_request_url: 'http://example.org/',
        http_response_headers: {},
        http_response_body_size: 2,
        http_response_status_code: 200,
        rails_controller_method: 'RSpec::Mocks::Double.test-action-name',
        rails_params: {
          'rubykey' => 'ruby-value'
        },
        rails_session_id: session_id
      )
      request.get('/')
    end
  end

  context 'when no controller is used' do
    let(:app) do
      lambda do |env|
        env['rack.session'] = { 'login_name' => login_name }
        env['rack.request.cookie_hash'] = {
          '_admin_panel_session_id' => session_id
        }
        [200, { 'Content-Type' => 'text/plain' }, ['OK']]
      end
    end

    it 'skips logging' do
      request.post('/', input: 'data', 'CONTENT_TYPE' => 'text/plain')
    end
  end

  context 'when no when login_name is added to env' do
    let(:app) do
      lambda do |env|
        allow(controller).to receive(:request)
          .and_return(ActionDispatch::Request.new(env))
        allow(controller).to receive(:response)
          .and_return(ActionDispatch::Response.new(200, {}, 'OK'))
        allow(controller).to receive(:action_name)
          .and_return('test-action-name')
        env['rack.request.cookie_hash'] = {
          '_admin_panel_session_id' => session_id
        }
        env['action_controller.instance'] = controller
        [200, { 'Content-Type' => 'text/plain' }, ['OK']]
      end
    end

    it 'skips logging' do
      request.post('/', input: 'data', 'CONTENT_TYPE' => 'text/plain')
    end
  end
end
