# frozen_string_literal: true

RSpec.describe DiscourseHub do
  describe ".discourse_version_check" do
    it "returns the JSON received from the hub" do
      hub_response = { "success" => "OK", "latest_version" => "0.8.1" }

      stub_request(
        :get,
        (ENV["HUB_BASE_URL"] || "http://local.hub:3000/api") + "/version_check",
      ).with(query: DiscourseHub.version_check_payload).to_return(
        status: 200,
        body: hub_response.to_json,
      )

      expect(DiscourseHub.discourse_version_check).to eq(hub_response)
    end
  end

  describe ".discover_enrollment" do
    it "sends a POST request to the hub" do
      stub_request(
        :post,
        (ENV["HUB_BASE_URL"] || "http://local.hub:3000/api") + "/discover/enroll",
      ).with(body: JSON[DiscourseHub.discover_enrollment_payload]).to_return(
        status: 200,
        body: "",
        headers: {
        },
      )

      DiscourseHub.discover_enrollment
    end
  end

  describe ".discover_enrollment_payload" do
    it "returns the configured payload" do
      payload = DiscourseHub.discover_enrollment_payload
      expect(payload[:forum_url]).to eq(Discourse.base_url)
      expect(payload[:forum_title]).to eq(SiteSetting.title)
      expect(payload[:locale]).to eq(I18n.locale)
    end
  end

  describe ".version_check_payload" do
    describe "when Discourse Hub has not fetched stats since past 7 days" do
      it "includes site statistics" do
        DiscourseHub.stats_fetched_at = 8.days.ago
        json = JSON.parse(DiscourseHub.version_check_payload.to_json)

        expect(json["topics_count"]).to be_present
        expect(json["posts_count"]).to be_present
        expect(json["users_count"]).to be_present
        expect(json["topics_7_days"]).to be_present
        expect(json["topics_30_days"]).to be_present
        expect(json["posts_7_days"]).to be_present
        expect(json["posts_30_days"]).to be_present
        expect(json["users_7_days"]).to be_present
        expect(json["users_30_days"]).to be_present
        expect(json["active_users_7_days"]).to be_present
        expect(json["active_users_30_days"]).to be_present
        expect(json["likes_count"]).to be_present
        expect(json["likes_7_days"]).to be_present
        expect(json["likes_30_days"]).to be_present
        expect(json["participating_users_7_days"]).to be_present
        expect(json["participating_users_30_days"]).to be_present
        expect(json["installed_version"]).to be_present
        expect(json["branch"]).to be_present
      end
    end

    describe "when Discourse Hub has fetched stats in past 7 days" do
      it "omits site statistics" do
        DiscourseHub.stats_fetched_at = 2.days.ago
        json = JSON.parse(DiscourseHub.version_check_payload.to_json)

        expect(json["topic_count"]).not_to be_present
        expect(json["post_count"]).not_to be_present
        expect(json["user_count"]).not_to be_present
        expect(json["like_count"]).not_to be_present
        expect(json["likes_7_days"]).not_to be_present
        expect(json["likes_30_days"]).not_to be_present
        expect(json["installed_version"]).to be_present
        expect(json["branch"]).to be_present
      end
    end

    describe "when send_anonymize_stats is disabled" do
      describe "when Discourse Hub has not fetched stats for the past year" do
        it "omits site statistics" do
          DiscourseHub.stats_fetched_at = 1.year.ago
          SiteSetting.share_anonymized_statistics = false
          json = JSON.parse(DiscourseHub.version_check_payload.to_json)

          expect(json["topic_count"]).not_to be_present
          expect(json["post_count"]).not_to be_present
          expect(json["user_count"]).not_to be_present
          expect(json["like_count"]).not_to be_present
          expect(json["likes_7_days"]).not_to be_present
          expect(json["likes_30_days"]).not_to be_present
          expect(json["installed_version"]).to be_present
          expect(json["branch"]).to be_present
        end
      end
    end
  end

  describe ".collection_action" do
    let(:fake_logger) { FakeLogger.new }

    before { Rails.logger.broadcast_to(fake_logger) }

    after { Rails.logger.stop_broadcasting_to(fake_logger) }

    it "logs errors from the hub request" do
      stub_request(:get, (ENV["HUB_BASE_URL"] || "http://local.hub:3000/api") + "/test").to_return(
        status: 500,
        body: "",
        headers: {
        },
      )

      DiscourseHub.collection_action(:get, "/test")

      expect(fake_logger.warnings).to eq([DiscourseHub.response_status_log_message("/test", 500)])

      expect(fake_logger.errors).to eq([DiscourseHub.response_body_log_message("")])
    end

    context "when raise_on_error is true" do
      it "raises DiscourseHub::Error with the parsed body on non-200 responses" do
        stub_request(
          :put,
          (ENV["HUB_BASE_URL"] || "http://local.hub:3000/api") + "/test",
        ).to_return(status: 422, body: { "error" => "Nope" }.to_json)

        expect { DiscourseHub.put("/test", {}, raise_on_error: true) }.to raise_error(
          DiscourseHub::Error,
        ) do |error|
          expect(error.status).to eq(422)
          expect(error.body).to eq("error" => "Nope")
        end
      end

      it "returns the parsed body on 200 responses" do
        stub_request(
          :put,
          (ENV["HUB_BASE_URL"] || "http://local.hub:3000/api") + "/test",
        ).to_return(status: 200, body: { "success" => true }.to_json)

        expect(DiscourseHub.put("/test", {}, raise_on_error: true)).to eq("success" => true)
      end
    end
  end
end
