require 'spec_helper'

describe ContentfulMiddleman::Tools::PreviewProxy do
  subject do
    preview_proxy = nil
    vcr('tools/preview_helper') {
      preview_proxy = described_class.instance(space: 'cfexampleapi', access_token: 'b4c0n73n7fu1', api_url: 'cdn.contentful.com')
    }
    preview_proxy
  end

  before(:each) do
    subject.clear_cache
  end

  describe 'class methods' do
    describe '::instance' do
    end

    it '::days' do
      expect(DateTime.new(2015, 1, 1, 0, 0, 0) + described_class.days(1)).to eq(DateTime.new(2015, 1, 2, 0, 0, 0))
    end

    it '::hours' do
      expect(DateTime.new(2015, 1, 1, 0, 0, 0) + described_class.hours(1)).to eq(DateTime.new(2015, 1, 1, 1, 0, 0))
    end

    it '::minutes' do
      expect(DateTime.new(2015, 1, 1, 0, 0, 0) + described_class.minutes(1)).to eq(DateTime.new(2015, 1, 1, 0, 1, 0))
    end

    it '::seconds' do
      expect(DateTime.new(2015, 1, 1, 0, 0, 0) + described_class.seconds(1)).to eq(DateTime.new(2015, 1, 1, 0, 0, 1))
    end
  end

  describe 'cache expiration can be configured' do
    before do
      described_class.class_variable_set(:@@instances, [])
    end

    after do
      described_class.class_variable_set(:@@instances, [])
    end

    it 'by tries' do
      preview = nil
      vcr('tools/preview_helper') {
        preview = described_class.instance(space: 'cfexampleapi', access_token: 'b4c0n73n7fu1', api_url: 'cdn.contentful.com', tries: 5)
      }

      vcr('tools/preview_helper/entries') {
        preview.entries
      }

      preview.entries
      preview.entries
      preview.entries
      preview.entries
      preview.entries

      expect { preview.entries }.to raise_error(VCR::Errors::UnhandledHTTPRequestError)
    end

    describe 'by expire time' do
      it 'will always refetch when expiry is before now' do
        preview = nil
        vcr('tools/preview_helper') {
          # Expired 5 minutes ago (will always refetch)
          preview = described_class.instance(space: 'cfexampleapi', access_token: 'b4c0n73n7fu1', api_url: 'cdn.contentful.com',  expires_in: described_class.minutes(-5))
        }

        vcr('tools/preview_helper/entries') {
          preview.entries
        }

        expect { preview.entries }.to raise_error(VCR::Errors::UnhandledHTTPRequestError)
      end

      it 'will never refetch until expired' do
        preview = nil
        vcr('tools/preview_helper') {
          # We put a ridiculously high number of tries to test expiration date
          preview = described_class.instance(space: 'cfexampleapi', access_token: 'b4c0n73n7fu1', api_url: 'cdn.contentful.com',  tries: 10000, expires_in: described_class.days(2))
        }

        vcr('tools/preview_helper/entries') {
          preview.entries
        }

        preview.entries
        preview.entries
        preview.entries
        preview.entries

        # ... this could go for 2 days straight without refetching ...

        preview.entries
        preview.entries
        preview.entries
        preview.entries

        # We force the cache to expire
        preview.clear_cache

        expect { preview.entries }.to raise_error(VCR::Errors::UnhandledHTTPRequestError)
      end
    end
  end

  describe 'instance methods' do
    describe '#entries' do
      it 'on first run fetches entries from preview api' do
        vcr('tools/preview_helper/entries') {
          subject.entries
        }
      end

      it 'on subsequent runs it doesnt' do
        vcr('tools/preview_helper/entries') {
          subject.entries
        }

        subject.entries
      end

      it 'but runs on different queries' do
        vcr('tools/preview_helper/entries') {
          subject.entries
        }

        subject.entries

        vcr('tools/preview_helper/entries_2') {
          subject.entries(content_type: 'cat')
        }
      end

      it 'caches taking into account the query' do
        vcr('tools/preview_helper/entries') {
          subject.entries
        }

        subject.entries

        vcr('tools/preview_helper/entries_2') {
          subject.entries(content_type: 'cat')
        }

        subject.entries(content_type: 'cat')
      end

      it 'forces a cache refresh after 3 consecutive queries' do
        vcr('tools/preview_helper/entries') {
          subject.entries
        }

        subject.entries
        subject.entries
        subject.entries

        expect { subject.entries }.to raise_error(VCR::Errors::UnhandledHTTPRequestError)
      end

      it 'should re-fetch after expire time' do
        vcr('tools/preview_helper/entries') {
          subject.entries
        }

        subject.instance_variable_get(:@cached_entry_collection)[Marshal.dump({})][:expires] = DateTime.now - 1

        expect { subject.entries }.to raise_error(VCR::Errors::UnhandledHTTPRequestError)
      end
    end

    describe '#assets' do
      it 'on first run fetches assets from preview api' do
        vcr('tools/preview_helper/assets') {
          subject.assets
        }
      end

      it 'on subsequent runs it doesnt' do
        vcr('tools/preview_helper/assets') {
          subject.assets
        }

        subject.assets
      end

      it 'but runs on different queries' do
        vcr('tools/preview_helper/assets') {
          subject.assets
        }

        subject.assets

        vcr('tools/preview_helper/assets_2') {
          subject.assets(order: 'sys.createdAt')
        }
      end

      it 'caches taking into account the query' do
        vcr('tools/preview_helper/assets') {
          subject.assets
        }

        subject.assets

        vcr('tools/preview_helper/assets_2') {
          subject.assets(order: 'sys.createdAt')
        }

        subject.assets(order: 'sys.createdAt')
      end

      it 'forces a cache refresh after 3 consecutive queries' do
        vcr('tools/preview_helper/assets') {
          subject.assets
        }

        subject.assets
        subject.assets
        subject.assets

        expect { subject.assets }.to raise_error(VCR::Errors::UnhandledHTTPRequestError)
      end

      it 'should re-fetch after expire time' do
        vcr('tools/preview_helper/assets') {
          subject.assets
        }

        subject.instance_variable_get(:@cached_asset_collection)[Marshal.dump({})][:expires] = DateTime.now - 1

        expect { subject.assets }.to raise_error(VCR::Errors::UnhandledHTTPRequestError)
      end
    end

    describe '#entry' do
      it 'on first run fetches entry from preview api' do
        vcr('tools/preview_helper/entry') {
          subject.entry('garfield')
        }
      end

      it 'on subsequent runs it doesnt' do
        vcr('tools/preview_helper/entry') {
          subject.entry('garfield')
        }

        subject.entry('garfield')
      end

      it 'but runs on different queries' do
        vcr('tools/preview_helper/entry') {
          subject.entry('garfield')
        }

        subject.entry('garfield')

        vcr('tools/preview_helper/entry_2') {
          subject.entry('happycat')
        }
      end

      it 'caches taking into account the query' do
        vcr('tools/preview_helper/entry') {
          subject.entry('garfield')
        }

        subject.entry('garfield')

        vcr('tools/preview_helper/entry_2') {
          subject.entry('happycat')
        }

        subject.entry('happycat')
      end

      it 'forces a cache refresh after 3 consecutive queries' do
        vcr('tools/preview_helper/entry') {
          subject.entry('garfield')
        }

        subject.entry('garfield')
        subject.entry('garfield')
        subject.entry('garfield')

        expect { subject.entry('garfield') }.to raise_error(VCR::Errors::UnhandledHTTPRequestError)
      end

      it 'should re-fetch after expire time' do
        vcr('tools/preview_helper/entry') {
          subject.entry('garfield')
        }

        subject.instance_variable_get(:@cached_entries)[Marshal.dump({cache_id: 'garfield'})][:expires] = DateTime.now - 1

        expect { subject.entry('garfield') }.to raise_error(VCR::Errors::UnhandledHTTPRequestError)
      end
    end

    describe '#asset' do
      it 'on first run fetches asset from preview api' do
        vcr('tools/preview_helper/asset') {
          subject.asset('nyancat')
        }
      end

      it 'on subsequent runs it doesnt' do
        vcr('tools/preview_helper/asset') {
          subject.asset('nyancat')
        }

        subject.asset('nyancat')
      end

      it 'but runs on different queries' do
        vcr('tools/preview_helper/asset') {
          subject.asset('nyancat')
        }

        subject.asset('nyancat')

        vcr('tools/preview_helper/asset_2') {
          subject.asset('happycat')
        }
      end

      it 'caches taking into account the query' do
        vcr('tools/preview_helper/asset') {
          subject.asset('nyancat')
        }

        subject.asset('nyancat')

        vcr('tools/preview_helper/asset_2') {
          subject.asset('happycat')
        }

        subject.asset('happycat')
      end

      it 'forces a cache refresh after 3 consecutive queries' do
        vcr('tools/preview_helper/asset') {
          subject.asset('nyancat')
        }

        subject.asset('nyancat')
        subject.asset('nyancat')
        subject.asset('nyancat')

        expect { subject.asset('nyancat') }.to raise_error(VCR::Errors::UnhandledHTTPRequestError)
      end

      it 'should re-fetch after expire time' do
        vcr('tools/preview_helper/asset') {
          subject.asset('nyancat')
        }

        subject.instance_variable_get(:@cached_assets)[Marshal.dump({cache_id: 'nyancat'})][:expires] = DateTime.now - 1

        expect { subject.asset('nyancat') }.to raise_error(VCR::Errors::UnhandledHTTPRequestError)
      end
    end
  end
end
