require "rails_helper"

describe RelatedContent do
  let(:parent_relationable) { create([:proposal, :debate].sample) }
  let(:child_relationable) { create([:proposal, :debate].sample) }
  let(:related_content) { build(:related_content) }

  it "is valid" do
    expect(related_content).to be_valid
  end

  it "allows relationables from various classes" do
    3.times do
      expect(build(:related_content,
                   parent_relationable: parent_relationable,
                   child_relationable: child_relationable)).to be_valid
    end
  end

  it "does not allow empty relationables" do
    expect(build(:related_content, parent_relationable: nil)).not_to be_valid
    expect(build(:related_content, child_relationable: nil)).not_to be_valid
  end

  it "does not allow repeated related contents" do
    related_content = create(:related_content,
                             parent_relationable: parent_relationable,
                             child_relationable: child_relationable,
                             author: build(:user))

    new_related_content = build(:related_content,
                                parent_relationable: related_content.parent_relationable,
                                child_relationable: related_content.child_relationable)

    expect(new_related_content).not_to be_valid
  end

  it "does not allow relating a content to itself" do
    related_content = build(:related_content,
                            parent_relationable: parent_relationable,
                            child_relationable: parent_relationable)

    expect(related_content).not_to be_valid
  end

  it "is not valid with an invalid parent relationable type" do
    related_content.parent_relationable_type = "NotARealModel"

    expect { related_content.valid? }.to raise_exception "uninitialized constant NotARealModel"
  end

  it "is not valid with parent relationable ID of a non-existent record" do
    related_content.parent_relationable_id = related_content.parent_relationable.class.last.id + 1

    expect(related_content).not_to be_valid
  end

  it "is not valid with an invalid child relationable type" do
    related_content.child_relationable_type = "NotARealModel"

    expect { related_content.valid? }.to raise_exception "uninitialized constant NotARealModel"
  end

  it "is not valid with child relationable ID of a non-existent record" do
    related_content.child_relationable_id = related_content.child_relationable.class.last.id + 1

    expect(related_content).not_to be_valid
  end

  describe "create_opposite_related_content" do
    let(:parent_relationable) { create(:proposal) }
    let(:child_relationable) { create(:debate) }
    let(:related_content) do
      build(:related_content,
            parent_relationable: parent_relationable,
            child_relationable: child_relationable,
            author: build(:user))
    end

    it "creates an opposite related_content" do
      expect { related_content.save }.to change { RelatedContent.count }.by(2)
      expect(related_content.opposite_related_content.child_relationable).to eq(parent_relationable)
      expect(related_content.opposite_related_content.parent_relationable).to eq(child_relationable)
    end
  end

  describe "#relationed_contents" do
    before do
      related_content = create(:related_content,
                               parent_relationable: parent_relationable,
                               child_relationable: create(:proposal),
                               author: build(:user))
      create(:related_content,
             parent_relationable: parent_relationable,
             child_relationable: child_relationable,
             author: build(:user))

      2.times do
        related_content.send(:score_positive, build(:user))
      end

      6.times do
        related_content.send(:score_negative, build(:user))
      end
    end

    it "returns not hidden by reports related contents" do
      expect(parent_relationable.relationed_contents).to eq [child_relationable]
    end

    it "returns related contents without withdrawn proposals" do
      create(
        :related_content,
        parent_relationable: parent_relationable,
        child_relationable: create(:proposal, :retired),
        author: build(:user)
      )
      expect(parent_relationable.relationed_contents).to eq [child_relationable]
    end
  end
end
