import { NgModule } from '@angular/core';
import { TestBed } from '@angular/core/testing';
import { EffectsModule } from '@ngrx/effects';
import { StoreModule, Store } from '@ngrx/store';
import { readFirst } from '@nx/angular/testing';

import * as <%= className %>Actions from './<%= fileName %>.actions';
import { <%= className %>Effects } from './<%= fileName %>.effects';
import { <%= className %>Facade } from './<%= fileName %>.facade';
import { <%= className %>Entity } from './<%= fileName %>.models';
import {
  <%= constantName %>_FEATURE_KEY,
  <%= className %>State,
  initial<%= className %>State,
  <%= propertyName %>Reducer
} from './<%= fileName %>.reducer';
import * as <%= className %>Selectors from './<%= fileName %>.selectors';

interface TestSchema {
  <%= propertyName %>: <%= className %>State;
}

describe('<%= className %>Facade', () => {
  let facade: <%= className %>Facade;
  let store: Store<TestSchema>;
  const create<%= className %>Entity = (id: string, name = ''): <%= className %>Entity => ({
    id,
    name: name || `name-${id}`
  });

  describe('used in NgModule', () => {
    beforeEach(() => {
      @NgModule({
        imports: [
          StoreModule.forFeature(<%= constantName %>_FEATURE_KEY, <%= propertyName %>Reducer),
          EffectsModule.forFeature([<%= className %>Effects])
        ],
        providers: [<%= className %>Facade]
      })
      class CustomFeatureModule {}

      @NgModule({
        imports: [
          StoreModule.forRoot({}),
          EffectsModule.forRoot([]),
          CustomFeatureModule,
        ]
      })
      class RootModule {}
      TestBed.configureTestingModule({ imports: [RootModule] });

      store = TestBed.inject(Store);
      facade = TestBed.inject(<%= className %>Facade);
    });

    /**
     * The initially generated facade::loadAll() returns empty array
     */
    it('loadAll() should return empty list with loaded == true', async () => {
      let list = await readFirst(facade.all<%= className %>$);
      let isLoaded = await readFirst(facade.loaded$);

      expect(list.length).toBe(0);
      expect(isLoaded).toBe(false);

      facade.init();

      list = await readFirst(facade.all<%= className %>$);
      isLoaded = await readFirst(facade.loaded$);

      expect(list.length).toBe(0);
      expect(isLoaded).toBe(true);
    });

    /**
     * Use `load<%= className %>Success` to manually update list
     */
    it('all<%= className %>$ should return the loaded list; and loaded flag == true', async () => {
      let list = await readFirst(facade.all<%= className %>$);
      let isLoaded = await readFirst(facade.loaded$);

      expect(list.length).toBe(0);
      expect(isLoaded).toBe(false);

      store.dispatch(<%= className %>Actions.load<%= className %>Success({
        <%= propertyName %>: [
          create<%= className %>Entity('AAA'),
          create<%= className %>Entity('BBB')
        ]})
      );

      list = await readFirst(facade.all<%= className %>$);
      isLoaded = await readFirst(facade.loaded$);

      expect(list.length).toBe(2);
      expect(isLoaded).toBe(true);
    });
  });
});
