import moment from 'moment';

import isBeforeDay from './isBeforeDay';
import isAfterDay from './isAfterDay';

export default function isDayVisible(day, month, numberOfMonths, enableOutsideDays) {
  if (!moment.isMoment(day)) return false;

  // Cloning is a little expensive, so we want to do it as little as possible.
  // Here we clone the month once and keep mutating that moment object.
  const mutableMonth = month.clone();

  const firstDayOfFirstMonth = enableOutsideDays
    ? mutableMonth.startOf('month').startOf('week')
    : mutableMonth.startOf('month');

  if (isBeforeDay(day, firstDayOfFirstMonth)) return false;

  const lastDayOfLastMonth = enableOutsideDays
    // We need to call endOf('week') when enableOutsideDays is true, because we
    // are reusing the moment object, and our earlier mutation may have moved it
    // to a previous month. This should snap us back to a good starting place.
    ? mutableMonth.endOf('week').add(numberOfMonths - 1, 'months').endOf('month').endOf('week')
    : mutableMonth.add(numberOfMonths - 1, 'months').endOf('month');

  return !isAfterDay(day, lastDayOfLastMonth);
}

@@ -102,16 +102,227 @@
 terDay';
+%0Aimport toISOMonthString from './toISOMonthString';%0A%0Aconst startCacheOutsideDays = new Map();%0Aconst endCacheOutsideDays = new Map();%0A%0Aconst startCacheInsideDays = new Map();%0Aconst endCacheInsideDays = new Map();
 %0A%0Aexport
@@ -528,186 +528,280 @@
 le.%0A
+%0A
   
-// Here we clone the month once and keep mutating that moment object.%0A  const mutableMonth = month.clone();%0A%0A  const firstDayOfFirstMonth = enableOutsideDays%0A    ? mutableMonth
+const startKey = toISOMonthString(month);%0A  // eslint-disable-next-line prefer-template%0A  const endKey = startKey + '+' + numberOfMonths;%0A%0A  if (enableOutsideDays) %7B%0A    if (!startCacheOutsideDays.has(startKey)) %7B%0A      startCacheOutsideDays.set(startKey, month.clone()
 .sta
@@ -833,509 +833,705 @@
 ek')
+);
 %0A    
-: mutableMonth.startOf('month');%0A%0A  if (isBeforeDay(day, firstDayOfFirstMonth)) return false;%0A%0A  const lastDayOfLastMonth = enableOutsideDays%0A    // We need to call endOf('week') when enableOutsideDays is true, because we%0A    // are reusing the moment object, and our earlier mutation may have moved it%0A    // to a previous month. This should snap us back to a good starting place.%0A    ? mutableMonth.endOf('week').add(numberOfMonths - 1, 'months').endOf('month').endOf('week')%0A
+%7D%0A%0A    if (isBeforeDay(day, startCacheOutsideDays.get(startKey))) return false;%0A%0A    if (!endCacheOutsideDays.has(endKey)) %7B%0A      endCacheOutsideDays.set(%0A        endKey,%0A        month.clone().endOf('week').add(numberOfMonths - 1, 'months').endOf('month')%0A          .endOf('week'),%0A      );%0A    %7D%0A%0A    return !isAfterDay(day, endCacheOutsideDays.get(endKey));%0A  %7D%0A%0A  // !enableOutsideDays%0A%0A  if (!startCacheInsideDays.has(startKey)) %7B%0A    startCacheInsideDays.set(startKey, month.clone().startOf('month'));%0A  %7D%0A%0A  if (isBeforeDay(day, startCacheInsideDays.get(startKey))) return false;%0A%0A  if (!endCacheInsideDays.has(endKey)) %7B%0A    endCacheInsideDays.set(%0A      endKey,%0A 
     
-:
  m
-utableMonth
+onth.clone()
 .add
@@ -1575,17 +1575,28 @@
 'month')
-;
+,%0A    );%0A  %7D
 %0A%0A  retu
@@ -1619,26 +1619,38 @@
 ay, 
-lastDayOfLastMonth
+endCacheInsideDays.get(endKey)
 );%0A%7D

Add caching to isDayVisible