import {Actions, TaskQueue} from 'nylas-exports'
import FeatureUsageStore from '../../src/flux/stores/feature-usage-store'
import Task from '../../src/flux/tasks/task'
import SendFeatureUsageEventTask from '../../src/flux/tasks/send-feature-usage-event-task'
import IdentityStore from '../../src/flux/stores/identity-store'

describe("FeatureUsageStore", function featureUsageStoreSpec() {
  beforeEach(() => {
    this.oldIdent = IdentityStore._identity;
    IdentityStore._identity = {id: 'foo'}
    IdentityStore._identity.feature_usage = {
      "is-usable": {
        quota: 10,
        period: 'monthly',
        used_in_period: 8,
        feature_limit_name: 'Usable Group A',
      },
      "not-usable": {
        quota: 10,
        period: 'monthly',
        used_in_period: 10,
        feature_limit_name: 'Unusable Group A',
      },
    }
  });

  afterEach(() => {
    IdentityStore._identity = this.oldIdent
  });

  describe("_isUsable", () => {
    it("returns true if a feature hasn't met it's quota", () => {
      expect(FeatureUsageStore._isUsable("is-usable")).toBe(true)
    });

    it("returns false if a feature is at its quota", () => {
      expect(FeatureUsageStore._isUsable("not-usable")).toBe(false)
    });

    it("warns if asking for an unsupported feature", () => {
      spyOn(NylasEnv, "reportError")
      expect(FeatureUsageStore._isUsable("unsupported")).toBe(false)
      expect(NylasEnv.reportError).toHaveBeenCalled()
    });
  });

  describe("_markFeatureUsed", () => {
    beforeEach(() => {
      spyOn(SendFeatureUsageEventTask.prototype, "performRemote").andReturn(Promise.resolve(Task.Status.Success));
      spyOn(IdentityStore, "saveIdentity").andCallFake((ident) => {
        IdentityStore._identity = ident
      })
      spyOn(TaskQueue, "waitForPerformLocal").andReturn(Promise.resolve())
      spyOn(Actions, 'queueTask').andCallFake((task) => {
        task.performLocal()
      })
    });

    afterEach(() => {
      TaskQueue._queue = []
    })

    it("returns the num remaining if successful", async () => {
      let numLeft = await FeatureUsageStore._markFeatureUsed('is-usable');
      expect(numLeft).toBe(1)
      numLeft = await FeatureUsageStore._markFeatureUsed('is-usable');
      expect(numLeft).toBe(0)
    });
  });

  describe("use feature", () => {
    beforeEach(() => {
      spyOn(FeatureUsageStore, "_markFeatureUsed").andReturn(Promise.resolve());
      spyOn(Actions, "openModal")
    });

    it("marks the feature used if you have pro access", async () => {
      spyOn(IdentityStore, "hasProAccess").andReturn(true);
      await FeatureUsageStore.asyncUseFeature('not-usable')
      expect(FeatureUsageStore._markFeatureUsed).toHaveBeenCalled();
      expect(FeatureUsageStore._markFeatureUsed.callCount).toBe(1);
    });

    it("marks the feature used if it's usable", async () => {
      spyOn(IdentityStore, "hasProAccess").andReturn(false);
      await FeatureUsageStore.asyncUseFeature('is-usable')
      expect(FeatureUsageStore._markFeatureUsed).toHaveBeenCalled();
      expect(FeatureUsageStore._markFeatureUsed.callCount).toBe(1);
    });

    describe("showing modal", () => {
      beforeEach(() => {
        this.hasProAccess = false;
        spyOn(IdentityStore, "hasProAccess").andCallFake(() => {
          return this.hasProAccess;
        })
        this.lexicon = {
          displayName: "Test Name",
          rechargeCTA: "recharge me",
          usedUpHeader: "all test used",
          iconUrl: "icon url",
        }
      });

      it("resolves the modal if you upgrade", async () => {
        setImmediate(() => {
          this.hasProAccess = true;
          FeatureUsageStore._onModalClose()
        })
        await FeatureUsageStore.asyncUseFeature('not-usable', {lexicon: this.lexicon});
        expect(Actions.openModal).toHaveBeenCalled();
        expect(Actions.openModal.calls.length).toBe(1)
      });

      it("pops open a modal with the correct text", async () => {
        setImmediate(() => {
          this.hasProAccess = true;
          FeatureUsageStore._onModalClose()
        })
        await FeatureUsageStore.asyncUseFeature('not-usable', {lexicon: this.lexicon});
        expect(Actions.openModal).toHaveBeenCalled();
        expect(Actions.openModal.calls.length).toBe(1)
        const component = Actions.openModal.calls[0].args[0].component;
        expect(component.props).toEqual({
          modalClass: "not-usable",
          featureName: "Test Name",
          headerText: "all test used",
          iconUrl: "icon url",
          rechargeText: "You’ll have 10 more next month",
        })
      });

      it("rejects if you don't upgrade", async () => {
        let caughtError = false;
        setImmediate(() => {
          this.hasProAccess = false;
          FeatureUsageStore._onModalClose()
        })
        try {
          await FeatureUsageStore.asyncUseFeature('not-usable', {lexicon: this.lexicon});
        } catch (err) {
          expect(err instanceof FeatureUsageStore.NoProAccess).toBe(true)
          caughtError = true;
        }
        expect(caughtError).toBe(true)
      });
    });
  });
});
