require "rails_helper"

RSpec.describe Profile do
  let(:user) { create(:user) }
  let(:profile) { user.profile }

  describe "validations" do
    subject { profile }

    it { is_expected.to validate_uniqueness_of(:user_id) }

    describe "conditionally validating summary" do
      let(:invalid_summary) { "x" * ProfileValidator::MAX_SUMMARY_LENGTH.next }

      it "is valid if users previously had long summaries and are grandfathered" do
        profile.summary = invalid_summary
        profile.save(validate: false)
        profile.summary = "x" * 999
        expect(profile).to be_valid
      end

      it "is not valid if the summary is too long and the user is not grandfathered" do
        profile.summary = invalid_summary
        expect(profile).not_to be_valid
        expect(profile.errors_as_sentence).to eq "Bio is too long"
      end

      it "is valid if the summary is less than the limit" do
        profile.summary = "Hello 👋"
        expect(profile).to be_valid
      end

      it "counts line ending as a single character when summary is multi line" do
        profile.summary = "#{'x' * ProfileValidator::MAX_SUMMARY_LENGTH.pred}\r\n"
        expect(profile).to be_valid
      end
    end

    describe "validating text areas" do
      let(:text_area_get) { ProfileField.find_by(label: "Test Text Area")&.attribute_name }
      let(:text_area_set) { "#{text_area_get}=" }

      before do
        create(:profile_field, label: "Test Text Area", input_type: :text_area)
      end

      it "is valid if the text is short enough" do
        profile.public_send(text_area_set, "Ruby")
        expect(profile).to be_valid
      end

      it "is invalid if the text is too long" do
        profile.public_send(text_area_set, "x" * ProfileValidator::MAX_TEXT_AREA_LENGTH.next)
        expect(profile).not_to be_valid
        expect(profile.errors_as_sentence)
          .to include("is too long (maximum is 200 characters)")
      end

      it "is valid if text contains new-lines within 200 characters" do
        profile.public_send(
          text_area_set,
          "Lorem Ipsum is simply dummy text of the printing and typesetting industry\r\nLorem Ipsum is simply dummy
text of the printing and typesetting industry\r\nLorem Ipsum is simply dummy text of the printing and",
        )

        expect(profile).to be_valid
      end
    end

    describe "validating text fields" do
      it "is valid if the text is short enough" do
        profile.location = "Somewhere"
        expect(profile).to be_valid
      end

      it "is invalid if the text is too long" do
        profile.location = "x" * ProfileValidator::MAX_TEXT_FIELD_LENGTH.next
        expect(profile).not_to be_valid
        expect(profile.errors_as_sentence).to eq "Location is too long (maximum is 100 characters)"
      end
    end

    describe "validating website_url" do
      it "is valid if blank" do
        profile.website_url = nil
        expect(profile).to be_valid
      end

      it "is valid with a complete url" do
        profile.website_url = "https://dev.to"
        expect(profile).to be_valid
      end

      it "is invalid with an incomplete url" do
        profile.website_url = "dev.to"
        expect(profile).not_to be_valid
        expect(profile.errors_as_sentence).to eq "Website url is not a valid URL"
      end
    end
  end

  context "when accessing profile fields" do
    before do
      create(:profile_field, label: "Test 1")
      create(:profile_field, label: "Test 2", input_type: :text_area)
    end

    let(:profile) { described_class.new }

    let(:test1) { ProfileField.find_by(label: "Test 1").attribute_name }
    let(:test2) { ProfileField.find_by(label: "Test 2").attribute_name }

    it "defines accessors for active profile fields", :aggregate_failures do
      expect(profile).to respond_to(test1)
      expect(profile).to respond_to(test2)
    end
  end
end
