/**
 * This file is part of Anis Client.
 *
 * @copyright Laboratoire d'Astrophysique de Marseille / CNRS
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

import { Injectable } from '@angular/core';
import { CanActivate, Router } from '@angular/router';

import { Store, select } from '@ngrx/store';
import { combineLatest, Observable } from 'rxjs';
import { switchMap, map, skipWhile } from 'rxjs/operators';

import * as instanceSelector from 'src/app/metamodel/selectors/instance.selector';
import * as instanceGroupSelector from 'src/app/metamodel/selectors/instance-group.selector';
import * as authSelector from 'src/app/auth/auth.selector';
import { AppConfigService } from 'src/app/app-config.service';
import { isAdmin } from 'src/app/shared/utils';

@Injectable({
    providedIn: 'root',
})
export class InstanceAuthGuard implements CanActivate {
    constructor(
        protected readonly router: Router,
        private store: Store<{ }>,
        private config: AppConfigService
    ) { }

    canActivate(): Observable<boolean> {
        return this.store.pipe(select(instanceSelector.selectInstanceListIsLoaded)).pipe(
            skipWhile(instanceListIsLoaded => !instanceListIsLoaded),
            switchMap(() =>  {
                return combineLatest([
                    this.store.pipe(select(instanceSelector.selectInstanceByRouteName)),
                    this.store.pipe(select(authSelector.selectUserRoles)),
                    this.store.pipe(select(authSelector.selectIsAuthenticated)),
                    this.store.pipe(select(instanceGroupSelector.selectAllInstanceGroups))
                ]).pipe(
                    map(([instance, userRoles, isAuthenticated, instanceGroupList]) => {
                        // No authorization required to continue
                        if (!this.config.authenticationEnabled 
                            || instance.public
                            || (isAuthenticated && isAdmin(this.config.adminRoles, userRoles))) {
                            return true;
                        }
        
                        // If user is authenticated and authorized so accessible changes to true
                        let accessible = false;
                        if (isAuthenticated) {
                            accessible = instanceGroupList
                                .filter(instanceGroup => instanceGroup.instances.includes(instance.name))
                                .filter(instanceGroup => userRoles.includes(instanceGroup.role))
                                .length > 0;
                        }
                        
                        // If user is not authorized to continue go to unauthorized page
                        if (!accessible) {
                            sessionStorage.setItem('redirect_uri', window.location.toString());
                            this.router.navigateByUrl('/unauthorized');
                            return false;
                        }
        
                        // Let "Router" allow user entering the page
                        return true;
                    })
                );
            })
        );
    }
}