import { ComponentFixture, TestBed, async, inject } from '@angular/core/testing';
import { provideMockStore, MockStore } from '@ngrx/store/testing';
import { Component, InjectionToken, Input } from '@angular/core';
import { Location } from '@angular/common';

import { DetailComponent } from './detail.component';
import * as fromDetail from '../store/detail.reducer';
import * as detailActions from '../store/detail.action';
import { Attribute, Family, Category } from 'src/app/metamodel/model';

describe('[Search] Container: DetailComponent', () => {
    @Component({ selector: 'app-object-display', template: '' })
    class ObjectDisplayStubComponent {
        @Input() datasetName: string;
        @Input() outputFamilyList: Family[];
        @Input() categoryList: Category[];
        @Input() attributeList: Attribute[];
        @Input() object: any;
        @Input() spectraIsLoading: boolean;
        @Input() spectraIsLoaded: boolean;
        @Input() spectraCSV: string;
    }

    let component: DetailComponent;
    let fixture: ComponentFixture<DetailComponent>;
    let store: MockStore;
    const initialState = {
        detail: { ...fromDetail.initialState }
    };
    const LOCATION_TOKEN = new InjectionToken<Location>('Window location object');

    beforeEach(async(() => {
        TestBed.configureTestingModule({
            declarations: [
                DetailComponent,
                ObjectDisplayStubComponent
            ],
            providers: [
                provideMockStore({ initialState }),
                { provide: LOCATION_TOKEN, useValue: window.history }
            ]
        });
        fixture = TestBed.createComponent(DetailComponent);
        component = fixture.componentInstance;
        store = TestBed.inject(MockStore);
    }));

    it('should create the component', () => {
        expect(component).toBeTruthy();
    });

    it('should execute ngOnInit lifecycle', (done) => {
        const initDetailAction = new detailActions.InitDetailAction();
        const spy = spyOn(store, 'dispatch');
        component.ngOnInit();
        Promise.resolve(null).then(function() {
            expect(spy).toHaveBeenCalledTimes(1);
            expect(spy).toHaveBeenCalledWith(initDetailAction);
            done();
        });
    });

    it ("#goBackToResult() should go to the previous location", inject([LOCATION_TOKEN], (location: Location) => {
        spyOn(location, 'back');
        component.goBackToResult();
        expect(location.back).toHaveBeenCalledTimes(1);
    }));

    it('#getSpectraCSV() should dispatch RetrieveSpectraAction', () => {
        const retrieveSpectraAction = new detailActions.RetrieveSpectraAction('toto');
        const spy = spyOn(store, 'dispatch');
        component.getSpectraCSV('toto');
        expect(spy).toHaveBeenCalledTimes(1);
        expect(spy).toHaveBeenCalledWith(retrieveSpectraAction);
    });

    it('#ngOnDestroy() should dispatch DestroyDetailAction', () => {
        const destroyDetailAction = new detailActions.DestroyDetailAction();
        const spy = spyOn(store, 'dispatch');
        component.ngOnDestroy();
        expect(spy).toHaveBeenCalledTimes(1);
        expect(spy).toHaveBeenCalledWith(destroyDetailAction);
    });
});