import { Injector, inject, isDevMode } from '@angular/core';
import { ActivatedRouteSnapshot, CanActivateFn, Router, RouterStateSnapshot } from '@angular/router';
import { map } from 'rxjs/operators';

import { AccountService } from 'app/core/auth/account.service';
import { StateStorageService } from './state-storage.service';
import { SecurityAction} from 'app/security/security-action.model';
import { Resources }   from 'app/security/resources.model';

/**
 * Used to secure a router path. 
 * Usage in *.routes.ts:
   const dashboardComponentRoute: Routes = [
    {
      path: ':id/view',
      component: DashboardComponentDetailComponent,
      resolve: {
        dashboardComponent: DashboardComponentResolve,
      },
      canActivate: [UserRouteAccessService],
      data: {
        action: SecurityAction.READ,
        resource: Resources.DASHBOARD_COMPONENT,
        service: DashboardComponentService
      }
    },
    (...)
 *
 * Can receive data[] args:
 *  - action - one of SecurityAction action
 *  - resource - the SecurityResource to evaluate permission
 *  - service - the EntityService
 * 
 * @param next 
 * @param state 
 * @returns 
 */
export const UserRouteAccessService: CanActivateFn = (next: ActivatedRouteSnapshot, state: RouterStateSnapshot) => {
  const injector = inject(Injector);
  const accountService = inject(AccountService);
  const router = inject(Router);
  const stateStorageService = inject(StateStorageService);

  return accountService.identity().pipe(
    map(account => {
      if (account) {
        let auth = true;  // Defaults to TRUE. ROLES or SecurityGroup must say otherwise

        // Check for ROLES (if any)
        const authorities = next.data['authorities'];

        if (authorities && authorities.length > 0) {
          auth = accountService.hasAnyAuthority(authorities);
          if (isDevMode() && !auth) {
            console.error('User does not have any of the required authorities:', authorities);
          }
        }

        // Check for permission in SecurityGroup, if it didn't failed before
        if (auth) {
          const actionToken: SecurityAction | null = next.data['action'];
          const resourceToken: Resources | null = next.data['resource'];
          const serviceToken = next.data['service'];

          if (actionToken && serviceToken && resourceToken) {
            // Make security evaluation with EntityService
            auth = accountService.evalPermission(resourceToken, actionToken);
            if (isDevMode() && !auth) {
              console.error('User does not have permisison to (action/resource) :', actionToken, resourceToken);
            }
          } 
        }

        if (!auth) router.navigate(['accessdenied']); 
        return auth;
      }

      stateStorageService.storeUrl(state.url);
      router.navigate(['/login']);
      return false;
    }),
  );
  
};
