import moment from 'moment';

import { startOfDay, daysSince, getPlanContext } from '../../../website/common/script/cron';

function localMoment (timeString, utcOffset) {
  return moment(timeString).utcOffset(utcOffset, true);
}

describe('cron utility functions', () => {
  describe('startOfDay', () => {
    it('is zero when no daystart configured', () => {
      const options = { now: moment('2020-02-02 09:30:00Z'), timezoneOffset: 0 };

      const result = startOfDay(options);

      expect(result).to.be.sameMoment('2020-02-02 00:00:00Z');
    });

    it('is zero when negative daystart configured', () => {
      const options = {
        now: moment('2020-02-02 09:30:00Z'),
        timezoneOffset: 0,
        daystart: -5,
      };

      const result = startOfDay(options);

      expect(result).to.be.sameMoment('2020-02-02 00:00:00Z');
    });

    it('is zero when daystart over 24 is configured', () => {
      const options = {
        now: moment('2020-02-02 09:30:00Z'),
        timezoneOffset: 0,
        daystart: 25,
      };

      const result = startOfDay(options);

      expect(result).to.be.sameMoment('2020-02-02 00:00:00Z');
    });

    it('is equal to daystart o\'clock when daystart configured', () => {
      const options = {
        now: moment('2020-02-02 09:30:00Z'),
        timezoneOffset: 0,
        dayStart: 5,
      };

      const result = startOfDay(options);

      expect(result).to.be.sameMoment('2020-02-02 05:00:00Z');
    });

    it('is previous day daystart o\'clock when daystart is after current time', () => {
      const options = {
        now: moment('2020-02-02 04:30:00Z'),
        timezoneOffset: 0,
        dayStart: 5,
      };

      const result = startOfDay(options);

      expect(result).to.be.sameMoment('2020-02-01 05:00:00Z');
    });

    it('is daystart o\'clock when daystart is after current time due to timezone', () => {
      const options = {
        now: moment('2020-02-02 04:30:00Z'),
        timezoneOffset: -120,
        dayStart: 5,
      };

      const result = startOfDay(options);

      expect(result).to.be.sameMoment('2020-02-02 05:00:00+02:00');
    });

    it('returns in default timezone if no timezone defined', () => {
      const utcOffset = moment().utcOffset();
      const now = localMoment('2020-02-02 04:30:00', utcOffset).utc();

      const result = startOfDay({ now });

      expect(result).to.be.sameMoment(localMoment('2020-02-02', utcOffset));
    });

    it('returns in default timezone if timezone lower than -12:00', () => {
      const utcOffset = moment().utcOffset();
      const options = {
        now: localMoment('2020-02-02 17:30:00', utcOffset).utc(),
        timezoneOffset: 721,
      };

      const result = startOfDay(options);

      expect(result).to.be.sameMoment(localMoment('2020-02-02', utcOffset));
    });

    it('returns in default timezone if timezone higher than +14:00', () => {
      const utcOffset = moment().utcOffset();
      const options = {
        now: localMoment('2020-02-02 07:32:25.376', utcOffset).utc(),
        timezoneOffset: -841,
      };

      const result = startOfDay(options);

      expect(result).to.be.sameMoment(localMoment('2020-02-02', utcOffset));
    });

    it('returns in overridden timezone if override present', () => {
      const options = {
        now: moment('2020-02-02 13:30:27Z'),
        timezoneOffset: 0,
        timezoneUtcOffsetOverride: -240,
      };

      const result = startOfDay(options);

      expect(result).to.be.sameMoment('2020-02-02 00:00:00-04:00');
    });

    it('returns start of yesterday if timezone difference carries it over datelines', () => {
      const offset = 300;
      const options = {
        now: moment('2020-02-02 04:30:00Z'),
        timezoneOffset: offset,
      };

      const result = startOfDay(options);

      expect(result).to.be.sameMoment(localMoment('2020-02-01', -offset));
    });
  });

  describe('daysSince', () => {
    it('correctly calculates days between two dates', () => {
      const now = moment();
      const dayBeforeYesterday = moment(now).subtract({ days: 2 });

      expect(daysSince(dayBeforeYesterday, { now })).to.equal(2);
    });

    it('is one lower if current time is before dayStart', () => {
      const oneWeekAgoAtOnePm = moment().hour(13).subtract({ days: 7 });
      const thisMorningThreeAm = moment().hour(3);
      const options = {
        now: thisMorningThreeAm,
        dayStart: 6,
      };

      const result = daysSince(oneWeekAgoAtOnePm, options);

      expect(result).to.equal(6);
    });

    it('is one higher if reference time is before dayStart and current time after dayStart', () => {
      const oneWeekAgoAtEightAm = moment().hour(8).subtract({ days: 7 });
      const todayAtFivePm = moment().hour(17);
      const options = {
        now: todayAtFivePm,
        dayStart: 11,
      };

      const result = daysSince(oneWeekAgoAtEightAm, options);

      expect(result).to.equal(8);
    });

    // Variations in timezone configuration options are already covered by startOfDay tests.
    it('uses now in user timezone as configured in options', () => {
      const timezoneOffset = 120;
      const options = {
        now: moment('1989-11-09 02:53:00+01:00'),
        timezoneOffset,
      };

      const result = daysSince(localMoment('1989-11-08', -timezoneOffset), options);

      expect(result).to.equal(0);
    });
  });

  describe('getPlanContext', () => {
    function baseUserData (count, offset, planId) {
      return {
        purchased: {
          plan: {
            consecutive: {
              count,
              offset,
              gemCapExtra: 26,
              trinkets: 19,
            },
            quantity: 1,
            extraMonths: 0,
            gemsBought: 0,
            owner: '116b4133-8fb7-43f2-b0de-706621a8c9d8',
            nextBillingDate: null,
            nextPaymentProcessing: null,
            planId,
            customerId: 'group-plan',
            dateUpdated: '2022-05-10T03:00:00.144+01:00',
            paymentMethod: 'Group Plan',
            dateTerminated: null,
            lastBillingDate: null,
            dateCreated: '2017-02-10T19:00:00.355+01:00',
          },
        },
      };
    }

    it('elapsedMonths is 0 if its the same month', () => {
      const user = baseUserData(60, 0, 'group_plan_auto');

      const planContext = getPlanContext(user, new Date(2022, 4, 20));
      expect(planContext.elapsedMonths).to.equal(0);
    });

    it('elapsedMonths is 1 after one month', () => {
      const user = baseUserData(60, 0, 'group_plan_auto');

      const planContext = getPlanContext(user, new Date(2022, 5, 11));

      expect(planContext.elapsedMonths).to.equal(1);
    });
  });
});
