import expect from 'expect';
import fetchMock from 'fetch-mock';

import {
  PageExpiry,
  getCacheControlHeader,
  MAX_STALE_WHILE_REVALIDATE_IN_SECONDS,
  buildCacheControlHeader,
} from 'mweb/server/selectors/cache';
import createTestState, {
  RootStateDeepPartial,
} from 'test/helpers/createTestState';
import { ChannelOnlineStatus } from 'mweb/common/reducers/data/channels';
import { Location } from 'mweb/common/reducers/app';
import { CHANNEL } from '../fetchMocks/liveToVODStatus';

describe('buildCacheControlHeader', () => {
  describe('when expiry is 0', () => {
    it('provides 0s for cache and stale time', () => {
      expect(buildCacheControlHeader(0 as PageExpiry)).toEqual(
        'public, max-age=0, stale-while-revalidate=0',
      );
    });
  });

  describe('when expiry is greater than max SWR', () => {
    it('provides proper values for max age and SWR', () => {
      expect(buildCacheControlHeader(60 as PageExpiry)).toEqual(
        'public, max-age=30, stale-while-revalidate=30',
      );
    });
  });

  describe('when expiry is equal to max SWR', () => {
    it('provides proper values for max age and SWR', () => {
      expect(buildCacheControlHeader(30 as PageExpiry)).toEqual(
        'public, max-age=0, stale-while-revalidate=30',
      );
    });
  });
});

describe('getCacheExpiry', () => {
  afterEach(() => {
    fetchMock.restore();
  });

  interface CacheExpiryTestCase {
    stateSeed?: RootStateDeepPartial;
    expectedAge: number;
    expectedSWR: number;
  }

  const CACHE_EXPIRY_TEST_CASES: CacheExpiryTestCase[] = [
    {
      expectedAge: PageExpiry.Default - MAX_STALE_WHILE_REVALIDATE_IN_SECONDS,
      expectedSWR: MAX_STALE_WHILE_REVALIDATE_IN_SECONDS,
    },
    {
      stateSeed: {
        app: {
          location: Location.Channel,
        },
      },
      expectedAge:
        PageExpiry.ChannelOffline - MAX_STALE_WHILE_REVALIDATE_IN_SECONDS,
      expectedSWR: MAX_STALE_WHILE_REVALIDATE_IN_SECONDS,
    },
    {
      stateSeed: {
        pages: { channelViewer: { currentChannel: CHANNEL } },
        app: {
          location: Location.Channel,
        },
        data: {
          channels: {
            channelDetails: {
              [CHANNEL]: { onlineStatus: ChannelOnlineStatus.Online },
            },
          },
        },
      },
      expectedAge:
        PageExpiry.ChannelOnline - MAX_STALE_WHILE_REVALIDATE_IN_SECONDS,
      expectedSWR: MAX_STALE_WHILE_REVALIDATE_IN_SECONDS,
    },
    {
      stateSeed: {
        pages: { channelViewer: { currentChannel: CHANNEL } },
        app: {
          location: Location.Channel,
        },
        data: {
          channels: {
            channelDetails: {
              [CHANNEL]: { onlineStatus: ChannelOnlineStatus.Offline },
            },
          },
        },
      },
      expectedAge:
        PageExpiry.ChannelOffline - MAX_STALE_WHILE_REVALIDATE_IN_SECONDS,
      expectedSWR: MAX_STALE_WHILE_REVALIDATE_IN_SECONDS,
    },
    {
      stateSeed: {
        pages: { channelViewer: { currentChannel: CHANNEL } },
        app: {
          location: Location.Channel,
        },
        data: {
          channels: {
            channelDetails: {
              [CHANNEL]: { onlineStatus: ChannelOnlineStatus.Unknown },
            },
          },
        },
      },
      expectedAge:
        PageExpiry.ChannelOffline - MAX_STALE_WHILE_REVALIDATE_IN_SECONDS,
      expectedSWR: MAX_STALE_WHILE_REVALIDATE_IN_SECONDS,
    },
    {
      stateSeed: {
        app: {
          location: Location.VOD,
        },
      },
      expectedAge: PageExpiry.VOD - MAX_STALE_WHILE_REVALIDATE_IN_SECONDS,
      expectedSWR: MAX_STALE_WHILE_REVALIDATE_IN_SECONDS,
    },
    {
      stateSeed: {
        app: {
          location: Location.ChatEmbed,
        },
      },
      expectedAge: PageExpiry.ChatEmbed - MAX_STALE_WHILE_REVALIDATE_IN_SECONDS,
      expectedSWR: MAX_STALE_WHILE_REVALIDATE_IN_SECONDS,
    },
    {
      stateSeed: {
        app: {
          status: 500,
        },
      },
      expectedAge: PageExpiry.Error,
      expectedSWR: 0,
    },
    {
      stateSeed: {
        app: {
          status: 404,
        },
      },
      expectedAge: PageExpiry.Default - MAX_STALE_WHILE_REVALIDATE_IN_SECONDS,
      expectedSWR: MAX_STALE_WHILE_REVALIDATE_IN_SECONDS,
    },
  ];

  CACHE_EXPIRY_TEST_CASES.forEach(({ stateSeed, expectedAge, expectedSWR }) => {
    const state = createTestState(stateSeed);
    const location = stateSeed && stateSeed.app && stateSeed.app.location;
    const status = (stateSeed && stateSeed.app && stateSeed.app.status) || 200;
    it(`generates the cache expiry for ${location} and status ${status}`, () => {
      expect(getCacheControlHeader(state)).toEqual(
        `public, max-age=${expectedAge}, stale-while-revalidate=${expectedSWR}`,
      );
    });
  });
});
