# frozen_string_literal: true

RSpec.shared_examples 'Expireable' do
  subject { described_class.new(expires_at: expires_at) }

  let(:expires_at) { nil }

  describe 'Scopes' do
    let!(:expired_record) do
      travel_to 2.days.ago do
        Fabricate factory_name, expires_at: 1.day.from_now
      end
    end
    let!(:un_expired_record) { Fabricate factory_name, expires_at: 10.days.from_now }

    describe '.expired' do
      it 'returns expired records' do
        expect(described_class.expired)
          .to include(expired_record)
          .and not_include(un_expired_record)
      end
    end
  end

  describe '#expires_in' do
    context 'when expires at is nil' do
      let(:expires_at) { nil }

      it 'returns nil' do
        expect(subject.expires_in)
          .to be_nil
      end
    end
  end

  describe '#expires_in=' do
    let(:record) { Fabricate.build factory_name }

    context 'when set to nil' do
      it 'sets expires_at to nil' do
        record.expires_in = nil
        expect(record.expires_at)
          .to be_nil
      end
    end

    context 'when set to empty' do
      it 'sets expires_at to nil' do
        record.expires_in = ''
        expect(record.expires_at)
          .to be_nil
      end
    end

    context 'when set to a value' do
      it 'sets expires_at to expected future time' do
        record.expires_in = 60
        expect(record.expires_at)
          .to be_within(0.1).of(60.seconds.from_now)
      end
    end
  end

  describe '#expired?' do
    context 'when expires_at is nil' do
      let(:expires_at) { nil }

      it { is_expected.to_not be_expired }
    end

    context 'when expires_at is in the past' do
      let(:expires_at) { 5.days.ago }

      it { is_expected.to be_expired }
    end

    context 'when expires_at is in the future' do
      let(:expires_at) { 5.days.from_now }

      it { is_expected.to_not be_expired }
    end

    describe '#expire!' do
      subject { Fabricate factory_name }

      it 'updates the timestamp' do
        expect { subject.expire! }
          .to change(subject, :expires_at)
      end
    end

    describe '#expires?' do
      context 'when value is missing' do
        let(:expires_at) { nil }

        it { is_expected.to_not be_expires }
      end

      context 'when value is present' do
        let(:expires_at) { 3.days.from_now }

        it { is_expected.to be_expires }
      end
    end
  end

  def factory_name
    described_class.name.underscore.to_sym
  end
end