require "spec_helper"

describe ZohoResourceClient do
  let(:resource_params) do
    {
      access_token: "1a2b3c",
      email: "email@example.org"
    }
  end

  let(:expected_request_headers) do
    {
      "Content-Type" => "application/json",
      "orgId" => "123",
      "Authorization" => "Zoho-oauthtoken 1a2b3c"
    }
  end

  let(:subject) { ZohoResourceClient.new(**resource_params) }

  before do
    stub_const("ArchiveConfig", OpenStruct.new(ArchiveConfig))
    ArchiveConfig.ZOHO_ORG_ID = "123"

    WebMock.disable_net_connect!
  end

  after do
    WebMock.allow_net_connect!
  end

  describe "#retrieve_contact_id" do
    context "for an existing contact" do
      before do
        WebMock.stub_request(:get, /zoho/)
          .with(query: hash_including({ email: "email@example.org" }))
          .to_return(headers: { content_type: "application/json" }, body: '{"data":[{"id":"1"}]}')
      end

      it "returns the contact id, without attempting to create a new one" do
        expect(subject.retrieve_contact_id).to eq("1")

        expect(WebMock).to have_requested(:get, "https://desk.zoho.com/api/v1/contacts/search")
          .with(
            headers: expected_request_headers,
            query: { email: "email@example.org", limit: 1, sortBy: "modifiedTime" }
          )

        expect(WebMock).not_to have_requested(:post, /zoho/)
      end
    end

    context "when no contact was found" do
      before do
        WebMock.stub_request(:get, /zoho/)
          .with(query: hash_including({ email: "email@example.org" }))
          .to_return(status: 204)

        WebMock.stub_request(:post, /zoho/)
          .to_return(headers: { content_type: "application/json" }, body: '{"id":"2"}')
      end

      it "creates a new contact using the email for the required field lastName" do
        expect(subject.retrieve_contact_id).to eq("2")

        expect(WebMock).to have_requested(:get, "https://desk.zoho.com/api/v1/contacts/search")
          .with(
            headers: expected_request_headers,
            query: { email: "email@example.org", limit: 1, sortBy: "modifiedTime" }
          )

        expect(WebMock).to have_requested(:post, "https://desk.zoho.com/api/v1/contacts")
          .with(
            headers: expected_request_headers,
            body: { "lastName" => "email@example.org", "email" => "email@example.org" }.to_json
          )
      end
    end
  end

  describe "#find_ticket" do
    context "for an existing ticket" do
      before do
        WebMock.stub_request(:get, /zoho/)
          .with(query: hash_including({ ticketNumber: "480000" }))
          .to_return(headers: { content_type: "application/json" }, body: '{"data":[{"ticketNumber":"480000"}]}')
      end

      it "returns the ticket content" do
        expect(subject.find_ticket(480_000).fetch("ticketNumber")).to eq("480000")

        expect(WebMock).to have_requested(:get, "https://desk.zoho.com/api/v1/tickets/search")
          .with(
            headers: expected_request_headers,
            query: { ticketNumber: "480000", limit: 1, sortBy: "modifiedTime" }
          )
      end
    end

    context "when no ticket was found" do
      before do
        WebMock.stub_request(:get, /zoho/)
          .with(query: hash_including({ ticketNumber: "480000" }))
          .to_return(status: 204)
      end

      it "returns nil" do
        expect(subject.find_ticket(480_000)).to be_nil
      end
    end

    context "when Zoho returns an error" do
      before do
        WebMock.stub_request(:get, /zoho/)
          .with(query: hash_including({ ticketNumber: "4" }))
          .to_return(status: 422, headers: { content_type: "application/json" }, body: '{"errorCode":"UNPROCESSABLE_ENTITY"}')
      end

      it "returns nil" do
        expect(subject.find_ticket(4)).to be_nil
      end
    end
  end

  describe "#create_ticket" do
    let(:ticket_attributes) do
      { foo: "bar" }
    end

    before do
      WebMock.stub_request(:post, /zoho/)
        .to_return(headers: { content_type: "application/json" }, body: '{"id":"3"}')
    end

    it "submits a post request to the correct endpoint with the expected arguments" do
      expect(subject.create_ticket(ticket_attributes: ticket_attributes).fetch("id")).to eq("3")

      expect(WebMock).to have_requested(:post, "https://desk.zoho.com/api/v1/tickets")
        .with(
          headers: expected_request_headers,
          body: ticket_attributes.to_json
        )
    end
  end

  describe "#create_ticket_attachment" do
    let(:attachment_attributes) do
      { file: "the_file" }
    end

    before do
      WebMock.stub_request(:post, /zoho/)
        .to_return(headers: { content_type: "application/json" }, body: '{"id":"31"}')
    end

    it "submits a post request to the correct endpoint with the expected arguments" do
      expect(subject.create_ticket_attachment(
        ticket_id: 3,
        attachment_attributes: attachment_attributes
      ).fetch("id")).to eq("31")

      expect(WebMock).to have_requested(:post, "https://desk.zoho.com/api/v1/tickets/3/attachments")
        .with(
          headers: expected_request_headers,
          body: "file=the_file"
        )
    end
  end
end
