# frozen_string_literal: true

RSpec.describe ReviewableNotesController do
  fab!(:admin)
  fab!(:moderator)
  fab!(:user)
  fab!(:reviewable, :reviewable_flagged_post)

  describe "#create" do
    context "when user is staff" do
      before { sign_in(admin) }

      it "creates a new reviewable note successfully" do
        post "/review/#{reviewable.id}/notes.json",
             params: {
               reviewable_note: {
                 content: "This is a test note",
               },
             }

        expect(response.status).to eq(200)

        json = response.parsed_body
        expect(json["content"]).to eq("This is a test note")
        expect(json["user"]["id"]).to eq(admin.id)
        expect(json["user"]["username"]).to eq(admin.username)

        # Verify note was actually created in database
        note = ReviewableNote.last
        expect(note.content).to eq("This is a test note")
        expect(note.user).to eq(admin)
        expect(note.reviewable).to eq(reviewable)
      end

      it "creates a new reviewable note successfully as a moderator" do
        sign_in(moderator)

        post "/review/#{reviewable.id}/notes.json",
             params: {
               reviewable_note: {
                 content: "Moderator note",
               },
             }

        expect(response.status).to eq(200)

        json = response.parsed_body
        expect(json["user"]["id"]).to eq(moderator.id)
      end

      it "returns validation errors for invalid content" do
        post "/review/#{reviewable.id}/notes.json", params: { reviewable_note: { content: "" } }

        expect(response.status).to eq(422)

        json = response.parsed_body
        expect(json["errors"]).to include("Content can't be blank")
      end

      it "returns validation errors for content that's too long" do
        long_content = "a" * (ReviewableNote::MAX_CONTENT_LENGTH + 1)

        post "/review/#{reviewable.id}/notes.json",
             params: {
               reviewable_note: {
                 content: long_content,
               },
             }

        expect(response.status).to eq(422)

        json = response.parsed_body
        expect(json["errors"]).to include(
          "Content is too long (maximum is #{ReviewableNote::MAX_CONTENT_LENGTH} characters)",
        )
      end

      it "trims whitespace from content" do
        post "/review/#{reviewable.id}/notes.json", params: { reviewable_note: { content: "   " } }

        expect(response.status).to eq(422)

        json = response.parsed_body
        expect(json["errors"]).to include("Content can't be blank")
      end

      it "handles missing reviewable" do
        post "/review/999999/notes.json", params: { reviewable_note: { content: "Test note" } }

        expect(response.status).to eq(404)
      end
    end

    context "when user is a category group moderator" do
      fab!(:group)
      fab!(:category_a, :category)
      fab!(:category_b, :category)
      fab!(:reviewable_in_a) do
        Fabricate(
          :reviewable_flagged_post,
          category: category_a,
          topic: Fabricate(:topic, category: category_a),
        )
      end
      fab!(:reviewable_in_b) do
        Fabricate(
          :reviewable_flagged_post,
          category: category_b,
          topic: Fabricate(:topic, category: category_b),
        )
      end

      before do
        SiteSetting.enable_category_group_moderation = true
        Fabricate(:category_moderation_group, category: category_a, group:)
        group.add(user)
        sign_in(user)
      end

      it "can create notes on reviewables in their moderated category" do
        post "/review/#{reviewable_in_a.id}/notes.json",
             params: {
               reviewable_note: {
                 content: "Note on my category",
               },
             }

        expect(response.status).to eq(200)
      end

      it "cannot create notes on reviewables in other categories" do
        post "/review/#{reviewable_in_b.id}/notes.json",
             params: {
               reviewable_note: {
                 content: "Should not work",
               },
             }

        expect(response.status).to eq(404)
      end
    end

    context "when user is not staff" do
      before { sign_in(user) }

      it "returns 403" do
        post "/review/#{reviewable.id}/notes.json",
             params: {
               reviewable_note: {
                 content: "This should fail",
               },
             }

        expect(response.status).to eq(403)
      end
    end

    context "when user is not logged in" do
      it "returns 403" do
        post "/review/#{reviewable.id}/notes.json",
             params: {
               reviewable_note: {
                 content: "This should fail",
               },
             }

        expect(response.status).to eq(403)
      end
    end
  end

  describe "#destroy" do
    fab!(:note) { Fabricate(:reviewable_note, reviewable: reviewable, user: admin) }

    context "when user is the note author" do
      before { sign_in(admin) }

      it "deletes the note successfully" do
        expect { delete "/review/#{reviewable.id}/notes/#{note.id}.json" }.to change {
          ReviewableNote.where(user: admin).count
        }.by(-1)

        expect(response.status).to eq(200)

        json = response.parsed_body
        expect(json["success"]).to eq("OK")
      end

      it "returns 404 for non-existent note" do
        delete "/review/#{reviewable.id}/notes/999999.json"
        expect(response.status).to eq(404)
      end
    end

    context "when user is admin but not the note author" do
      fab!(:moderator_note) { Fabricate(:reviewable_note, reviewable: reviewable, user: moderator) }

      before { sign_in(admin) }

      it "allows admin to delete any note" do
        expect { delete "/review/#{reviewable.id}/notes/#{moderator_note.id}.json" }.to change {
          ReviewableNote.count
        }.by(-1)

        expect(response.status).to eq(200)
      end
    end

    context "when user is moderator but not admin and not note author" do
      fab!(:admin_note) { Fabricate(:reviewable_note, reviewable: reviewable, user: admin) }

      before { sign_in(moderator) }

      it "returns 403" do
        delete "/review/#{reviewable.id}/notes/#{admin_note.id}.json"
        expect(response.status).to eq(403)
      end
    end

    context "when user is not staff" do
      before { sign_in(user) }

      it "returns 403" do
        delete "/review/#{reviewable.id}/notes/#{note.id}.json"
        expect(response.status).to eq(403)
      end
    end

    context "when user is not logged in" do
      it "returns 403" do
        delete "/review/#{reviewable.id}/notes/#{note.id}.json"
        expect(response.status).to eq(403)
      end
    end

    context "when reviewable doesn't exist" do
      before { sign_in(admin) }

      it "returns 404" do
        delete "/review/999999/notes/#{note.id}.json"
        expect(response.status).to eq(404)
      end
    end

    context "when note belongs to different reviewable" do
      fab!(:other_reviewable, :reviewable_flagged_post)
      fab!(:other_note) { Fabricate(:reviewable_note, reviewable: other_reviewable, user: admin) }

      before { sign_in(admin) }

      it "returns 404" do
        delete "/review/#{reviewable.id}/notes/#{other_note.id}.json"
        expect(response.status).to eq(404)
      end
    end
  end
end
