describe "Publishing a pact" do

  let(:pact_content) { load_fixture("a_consumer-a_provider.json") }
  let(:path) { "/pacts/provider/A%20Provider/consumer/A%20Consumer/version/1.2.3" }
  let(:response_body_json) { JSON.parse(subject.body) }
  let(:rack_env) do
    {
      "CONTENT_TYPE" => "application/json",
      "pactbroker.database_connector" => lambda { |&block| block.call }
    }
  end

  subject { put(path, pact_content, rack_env)  }

  context "when a pact for this consumer version does not exist" do
    it "returns a 201 Created" do
      expect(subject.status).to be 201
    end

    it "returns a json body" do
      expect(subject.headers["Content-Type"]).to eq "application/hal+json;charset=utf-8"
    end

    it "returns the pact in the body" do
      expect(response_body_json).to match_pact JSON.parse(pact_content)
    end
  end

  context "when a pact for this consumer version does exist" do
    before do
      td.create_pact_with_hierarchy("A Consumer", "1.2.3", "A Provider").and_return(:pact)
      allow(PactBroker.configuration).to receive(:allow_dangerous_contract_modification).and_return(allow_dangerous_contract_modification)
    end

    context "when the content is different" do
      context "when pact modification is allowed" do
        let(:allow_dangerous_contract_modification) { true }

        it "returns a 200 Success" do
          expect(subject.status).to be 200
        end

        it "returns an application/json Content-Type" do
          expect(subject.headers["Content-Type"]).to eq "application/hal+json;charset=utf-8"
        end

        it "returns the pact in the response body" do
          expect(response_body_json).to match_pact JSON.parse(pact_content)
        end
      end
    end

    context "when pact modification is not allowed" do
      let(:allow_dangerous_contract_modification) { false }

      its(:status) { is_expected.to eq 409 }
      its(:body) { is_expected.to include "Cannot change the content of the pact for A Consumer version 1.2.3" }

      context "with an empty body" do
        let(:pact_content) { "" }

        its(:status) { is_expected.to eq 400 }
      end
    end

  end

  context "when the pacticipant names in the path do not match those in the pact" do
    let(:path) { "/pacts/provider/Another%20Provider/consumer/A%20Consumer/version/1.2.3" }

    it "returns a json error response" do
      expect(subject).to be_a_json_error_response "does not match"
    end
  end

  context "when the pacticipant name is an almost duplicate of an existing pacticipant name" do
    before do
      td.create_pacticipant("A Provider Service")
    end

    context "when duplicate checking is on" do
      before do
        PactBroker.configuration.check_for_potential_duplicate_pacticipant_names = true
      end

      it "returns a 409" do
        expect(subject.status).to eq 409
      end
    end

    context "when duplicate checking is off" do
      before do
        PactBroker.configuration.check_for_potential_duplicate_pacticipant_names = false
      end

      it "returns a 201" do
        expect(subject.status).to eq 201
      end
    end
  end

  context "with a webhook configured", job: true do
    before do
      td.create_webhook(
        method: "POST",
        url: "http://example.org",
        events: [{ name: PactBroker::Webhooks::WebhookEvent::CONTRACT_PUBLISHED }]
      )
    end
    let!(:request) do
      stub_request(:post, "http://example.org").to_return(:status => 200)
    end

    it "executes the webhook" do
      subject
      expect(request).to have_been_made
    end

    context "when an error occurs rendering the pact" do
      before do
        allow_any_instance_of(PactBroker::Api::Decorators::PactDecorator).to receive(:to_json).and_raise("an error")
      end

      it "does not execute the webhook" do
        subject
        expect(request).to_not have_been_made
      end
    end
  end
end
