# frozen_string_literal: true

describe DownloadTV::Torrent do
  let(:default_grabber) { nil }
  let(:eztv_mock) { double('eztv') }
  let(:torrentapi_mock) { double('torrentapi') }
  let(:torrentz_mock) { double('torrentz') }
  let(:tpb_mock) { double('tpb') }
  let(:test_show) { double('test_show') }
  subject { described_class.new(default_grabber) }

  before :each do
    allow(DownloadTV::TorrentAPI).to receive(:new).and_return torrentapi_mock
    allow(DownloadTV::Torrentz).to receive(:new).and_return torrentz_mock
    allow(DownloadTV::Eztv).to receive(:new).and_return eztv_mock
    # allow(DownloadTV::ThePirateBay).to receive(:new).and_return tpb_mock

    allow(torrentapi_mock).to receive(:online?).and_return(true)
    allow(torrentz_mock).to receive(:online?).and_return(true)
    allow(eztv_mock).to receive(:online?).and_return(true)
  end

  describe 'Torrent.grabbers' do
    it 'returns the list of grabbers' do
      # This order is assumed in the other specs, so explicitly checking it here
      expect(described_class.grabbers).to eq %w[TorrentAPI Torrentz Eztv]

    end
  end

  describe '#get_links' do
    it 'will use the first grabber and return its #get_link result' do
      result = double('result')
      expect(torrentapi_mock).to receive(:get_links).with(test_show).and_return(result)

      result = subject.get_links(test_show)
    end

    context 'when the first grabber is offline' do
      before do
        allow(torrentapi_mock).to receive(:online?).and_return(false)
      end

      it 'will use the second grabber' do
        expect(torrentapi_mock).not_to receive(:get_links)
        expect(eztv_mock).not_to receive(:get_links)
        expect(torrentz_mock).to receive(:get_links).with(test_show)

        result = subject.get_links(test_show)
      end
    end

    context 'when all the grabbers are offline' do
      before do
        allow(torrentapi_mock).to receive(:online?).and_return(false)
        allow(torrentz_mock).to receive(:online?).and_return(false)
        allow(eztv_mock).to receive(:online?).and_return(false)
      end

      it 'will exit' do
        expect(torrentapi_mock).not_to receive(:get_links)
        expect(torrentz_mock).not_to receive(:get_links)
        expect(eztv_mock).not_to receive(:get_links)

        expect { subject.get_links(test_show) }.to raise_error(SystemExit)
      end
    end

    context 'when one grabber does not find a link' do
      before do
        allow(torrentapi_mock).to receive(:get_links).with(test_show).and_raise(DownloadTV::NoTorrentsError)
        allow(torrentz_mock).to receive(:get_links).with(test_show).and_raise(DownloadTV::NoTorrentsError)
      end

      it 'will keep trying until one does' do
        expect(torrentapi_mock).to receive(:get_links).ordered
        expect(torrentz_mock).to receive(:get_links).ordered
        expect(eztv_mock).to receive(:get_links).ordered

        result = subject.get_links(test_show)
      end
    end

    context 'when no grabber can find a link' do
      before do
        allow(torrentapi_mock).to receive(:get_links).with(test_show).and_raise(DownloadTV::NoTorrentsError)
        allow(torrentz_mock).to receive(:get_links).with(test_show).and_raise(DownloadTV::NoTorrentsError)
        allow(eztv_mock).to receive(:get_links).with(test_show).and_raise(DownloadTV::NoTorrentsError)
      end

      it 'will return an empty array' do
        expect(torrentapi_mock).to receive(:get_links).ordered
        expect(torrentz_mock).to receive(:get_links).ordered
        expect(eztv_mock).to receive(:get_links).ordered

        expect(subject.get_links(test_show)).to eq []
      end
    end

    context 'when the default grabber is set' do
      let(:default_grabber) { 'Eztv' }

      it 'will use that grabber preferently' do
        test_show = double('test_show')
        expect(torrentapi_mock).not_to receive(:get_links)
        expect(torrentz_mock).not_to receive(:get_links)
        expect(eztv_mock).to receive(:get_links).with(test_show)

        result = subject.get_links(test_show)
      end
    end

    context 'when a grabber fails on a run and it is called twice' do
      before do
        count = 0
        allow(torrentapi_mock).to receive(:get_links).exactly(2).times.with(test_show) do
          count += 1
          raise DownloadTV::NoTorrentsError if count == 1
        end

      end

      it 'the second run will use the original order' do
        expect(torrentapi_mock).to receive(:get_links).exactly(2).times
        expect(torrentz_mock).to receive(:get_links).exactly(1).time

        result = subject.get_links(test_show)
        result = subject.get_links(test_show)
      end
    end
  end
end