# frozen_string_literal: true

shared_examples 'an item rep collection view' do
  let(:view) { described_class.new(wrapped, view_context) }

  let(:view_context) { nil }

  let(:wrapped) do
    [
      double(:item_rep, name: :foo),
      double(:item_rep, name: :bar),
      double(:item_rep, name: :baz),
    ]
  end

  describe '#_unwrap' do
    subject { view._unwrap }

    it { is_expected.to equal(wrapped) }
  end

  describe '#frozen?' do
    subject { view.frozen? }

    context 'non-frozen collection' do
      it { is_expected.to be(false) }
    end

    context 'frozen collection' do
      before { wrapped.freeze }

      it { is_expected.to be(true) }
    end
  end

  describe '#each' do
    it 'yields' do
      actual = [].tap { |res| view.each { |v| res << v } }
      expect(actual.size).to eq(3)
    end

    it 'returns self' do
      res = view.each do |_i|
        # do nothing
      end

      expect(res).to equal(view)
    end

    it 'yields elements with the right context' do
      view.each { |v| expect(v._context).to equal(view_context) }
    end
  end

  describe '#size' do
    subject { view.size }

    it { is_expected.to eq 3 }
  end

  describe '#to_ary' do
    subject { view.to_ary }

    it 'returns an array of item rep views' do
      expect(subject.class).to eq(Array)
      expect(subject.size).to eq(3)
      expect(subject[0].class).to eql(expected_view_class)
      expect(subject[0].name).to be(:foo)
    end

    it 'returns an array with correct contexts' do
      expect(subject[0]._context).to equal(view_context)
    end
  end

  describe '#[]' do
    subject { view[name] }

    context 'when not found' do
      let(:name) { :donkey }

      it { is_expected.to be_nil }
    end

    context 'when found' do
      let(:name) { :foo }

      it 'returns a view' do
        expect(subject.class).to eq(expected_view_class)
        expect(subject.name).to eq(:foo)
      end

      it 'returns a view with the correct context' do
        expect(subject._context).to equal(view_context)
      end
    end

    context 'when given a string' do
      let(:name) { 'foo' }

      it 'raises' do
        expect do
          subject
        end.to raise_error(
          ArgumentError, 'expected BasicItemRepCollectionView#[] to be called with a symbol'
        )
      end
    end

    context 'when given a number' do
      let(:name) { 0 }

      it 'raises' do
        expect do
          subject
        end.to raise_error(
          ArgumentError,
          'expected BasicItemRepCollectionView#[] to be called with a symbol ' \
          '(you likely want `.reps[:default]` rather than `.reps[0]`)',
        )
      end
    end
  end

  describe '#fetch' do
    subject { view.fetch(name) }

    context 'when not found' do
      let(:name) { :donkey }

      it 'raises' do
        expect { subject }.to raise_error(Nanoc::Core::BasicItemRepCollectionView::NoSuchItemRepError)
      end
    end

    context 'when found' do
      let(:name) { :foo }

      it 'returns a view' do
        expect(subject.class).to eq(expected_view_class)
        expect(subject.name).to eq(:foo)
      end

      it 'returns a view with the correct context' do
        expect(subject._context).to equal(view_context)
      end
    end
  end

  describe '#inspect' do
    subject { view.inspect }

    it { is_expected.to eql("<#{described_class.name}>") }
  end
end
