import { Component, Input } from '@angular/core';
import { TestBed, waitForAsync, ComponentFixture  } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';

import { provideMockStore, MockStore } from '@ngrx/store/testing';
import { of } from 'rxjs';

import { PortalHomeComponent } from './portal-home.component';
import { AppConfigService } from 'src/app/app-config.service';
import { UserProfile } from 'src/app/auth/user-profile.model';
import { Instance } from 'src/app/metamodel/models';
import * as authActions from 'src/app/auth/auth.actions';

describe('PortalHomeComponent', () => {
    @Component({ selector: 'app-navbar', template: '' })
    class NavbarStubComponent {
        @Input() links: { label: string, icon: string, routerLink: string }[];
        @Input() isAuthenticated: boolean;
        @Input() userProfile: UserProfile = null;
        @Input() baseHref: string;
        @Input() authenticationEnabled: boolean;
    }

    @Component({ selector: 'app-instance-card', template: '' })
    class InstanceCardStubComponent {
        @Input() instance: Instance;
    }

    let component: PortalHomeComponent;
    let fixture: ComponentFixture<PortalHomeComponent>;
    let store: MockStore;
    let appConfigServiceStub = new AppConfigService();

    beforeEach(waitForAsync(() => {
        TestBed.configureTestingModule({
            imports: [RouterTestingModule],
            declarations: [
                PortalHomeComponent,
                NavbarStubComponent,
                InstanceCardStubComponent
            ],
            providers: [
                provideMockStore({ }),
                { provide: AppConfigService, useValue: appConfigServiceStub }
            ]
        }).compileComponents();
        fixture = TestBed.createComponent(PortalHomeComponent);
        component = fixture.componentInstance;
        store = TestBed.inject(MockStore);
        document.body.innerHTML = '<link id="favicon" href="">';
    }));

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

    it('should execute ngOnInit lifecycle and add admin link if no authentication', () => {
        appConfigServiceStub.authenticationEnabled = false;
        component.ngOnInit();
        const expected = [
            { label: 'Home', icon: 'fas fa-home', routerLink: '/portal' },
            { label: 'Admin', icon: 'fas fa-tools', routerLink: '/admin' }
        ];
        expect(component.links).toEqual(expected);
        expect(component.favIcon.href).toEqual('http://localhost/favicon.ico');
    });

    it('should execute ngOnInit lifecycle and add admin link depending on user rights', () => {
        appConfigServiceStub.authenticationEnabled = true;
        appConfigServiceStub.adminRole = 'admin';
        component.userRoles = of([]);
        component.ngOnInit();
        expect(component.links).toEqual([{ label: 'Home', icon: 'fas fa-home', routerLink: '/portal' }]);
        component.userRoles = of(['admin']);
        component.ngOnInit();
        const expected = [
            { label: 'Home', icon: 'fas fa-home', routerLink: '/portal' },
            { label: 'Admin', icon: 'fas fa-tools', routerLink: '/admin' }
        ];
        expect(component.links).toEqual(expected);

    });

    it('#getBaseHref() should return base href config key value', () => {
        appConfigServiceStub.baseHref = '/my-project';
        expect(component.getBaseHref()).toBe('/my-project');
    });

    it('#authenticationEnabled() should return authentication enabled config key value', () => {
        appConfigServiceStub.authenticationEnabled = true;
        expect(component.getAuthenticationEnabled()).toBeTruthy();
    });

    it('#login() should dispatch login action', () => {
        const spy = jest.spyOn(store, 'dispatch');
        component.login();
        expect(spy).toHaveBeenCalledTimes(1);
        expect(spy).toHaveBeenCalledWith(authActions.login());
    });

    it('#logout() should dispatch logout action', () => {
        const spy = jest.spyOn(store, 'dispatch');
        component.logout();
        expect(spy).toHaveBeenCalledTimes(1);
        expect(spy).toHaveBeenCalledWith(authActions.logout());
    });

    it('#openEditProfile() should dispatch open edit profile action', () => {
        const spy = jest.spyOn(store, 'dispatch');
        component.openEditProfile();
        expect(spy).toHaveBeenCalledTimes(1);
        expect(spy).toHaveBeenCalledWith(authActions.openEditProfile());
    });

    it('should unsubscribe to user roles when component is destroyed', () => {
        component.userRolesSubscription = of().subscribe();
        const spy = jest.spyOn(component.userRolesSubscription, 'unsubscribe');
        component.ngOnDestroy();
        expect(spy).toHaveBeenCalledTimes(1);
    });
});