require 'rails_helper'

RSpec.describe MessagesController, type: :request do

  let(:shard_id) { rand(100..200).to_s }
  let(:body) do
    {some_json: "something"}.to_json
  end

  let(:headers) {
    {
      "X-Forwarded-Proto" => "https",
      "Content-Type" => "application/json",
      "Conductor-Shard-Tag" => shard_id,
      "Some-Random-Header" => "Totally Random"
    }
  }

  describe "#create" do
    context 'autogenerate shard' do
      before do
        allow(ENV).to receive(:[]).and_call_original
        allow(ENV).to receive(:[]).with('AUTOGENERATE_SHARD_ID').and_return 'true'
        allow(ENV).to receive(:[]).with('AUTOGENERATE_SHARD_ID_RANGE').and_return '3'
        Settings.reload!
      end

      let(:headers) {
        {
          "X-Forwarded-Proto" => "https",
          "Content-Type" => "application/json",
          "Some-Random-Header" => "Totally Random"
        }
      }

      it 'creates messages with the autogenerated shard' do
        shard_ids = []
        8.times do
          post "/messages", body, headers
          shard_ids << Message.last.shard_id.to_i
        end
        expect(shard_ids).to all( be <= 3 )
      end
    end

    it "responds with 200" do
      post "/messages", body, headers
      expect(response.code).to eq "200"
    end

    it "creates the message" do
      expect {
        post "/messages", body, headers
      }.to change { Message.count }.by 1
    end

    context "enable header" do

      context "not sent" do
        it "sets needs_sending as true" do
          post "/messages", body, headers
          expect(Message.last.needs_sending).to be true
        end
      end

      context "sent" do
        before do
          headers["Conductor-Enabled-Tag"] = "true"
        end

        it "sets needs_sending to true" do
          post "/messages", body, headers
          expect(Message.last.needs_sending).to be true
        end
      end

      context "sent as false" do
        before do
          headers["Conductor-Enabled-Tag"] = "false"
        end

        it "sets needs_sending to true" do
          post "/messages", body, headers
          expect(Message.last.needs_sending).to be false
        end
      end
    end

    it "captures the body" do
      post "/messages", body, headers
      message = Message.last
      expect(message.body).to eq body
    end

    it "assigns the shard_id" do
      post "/messages", body, headers
      message = Message.last
      expect(message.shard_id).to eq shard_id
    end

    it "captures the headers like a proxy" do
      post "/messages", body, headers
      message = Message.last

      message_headers = JSON.parse(message.headers)

      message_headers.delete("Accept")

      expect(message_headers['Content-type']).to eq "application/json"

      expect(message_headers).to have_key('X-Forwarded-Host')
      expect(message_headers).to have_key('X-Forwarded-Port')
      expect(message_headers).to have_key('X-Forwarded-For')

      message_headers.delete('Content-type')
      message_headers.delete('X-Forwarded-For')
      message_headers.delete('X-Forwarded-Host')
      port = message_headers.delete('X-Forwarded-Port')

      expect(port.class).to be String

      expect(message_headers).to eq({
        "Cookie" => "",
        "X-forwarded-proto" => "https",
        "Conductor-shard-tag" => shard_id.to_s,
        "Some-random-header" => "Totally Random"
      })
    end

    it "preserves a history of X-Forwarded-For" do
      headers = {
        "X-Forwarded-For" => "123.123.123.123, 234.234.234.234",
      }

      post "/messages", body, headers
      expect(response.code).to eq "200"
      message = Message.last

      message_headers = JSON.parse(message.headers)
      expect(message_headers['X-Forwarded-For']).to eq "123.123.123.123, 234.234.234.234, 127.0.0.1"
    end

    it "doesn't save the Host header" do
      headers = {
        "Host" => "some.host.com",
      }

      post "/messages", body, headers
      expect(response.code).to eq "200"
      message = Message.last

      message_headers = JSON.parse(message.headers)
      expect(message_headers).to_not have_key("Host")
    end
  end
end
