import { Injectable } from '@angular/core';
import {ApiService} from './api.service';
import {ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot} from '@angular/router';
import {LocalStorageService} from 'angular-2-local-storage';
import {Observable} from 'rxjs';
import {DataService} from './data.service';

@Injectable({
  providedIn: 'root'
})
export class LoginService implements CanActivate {

  private pathPermissions = [  // minimum level needed for the specified paths
    {path: 'materials', permission: 'dev'},
    {path: 'templates', permission: 'dev'},
    {path: 'changelog', permission: 'dev'},
    {path: 'users', permission: 'admin'}
  ];
  readonly levels = [  // all user levels in ascending permissions order
    'predict',
    'read',
    'write',
    'dev',
    'admin'
  ];
  // returns true or false depending on whether the user fulfills the minimum level
  isLevel: {[level: string]: boolean} = {};
  hasPrediction = false;  // true if user has prediction models specified
  userId = '';

  private loggedIn;

  constructor(
    private api: ApiService,
    private storage: LocalStorageService,
    private router: Router,
    private d: DataService
  ) {

  }

  login(username = '', password = '') {
    return new Promise(resolve => {
      if (username !== '' || password !== '') {  // some credentials given
        let credentials: string[];
        const credentialString: string = this.storage.get('basicAuth');
        if (credentialString) {  // found stored credentials
          credentials = atob(credentialString).split(':');
        }
        else {
          credentials = ['', ''];
        }
        if (username !== '' && password !== '') {  // all credentials given
          this.storage.set('basicAuth', btoa(username + ':' + password));
        }
        else if (username !== '') {  // username given
          this.storage.set('basicAuth', btoa(username + ':' + credentials[1]));
        }
        else if (password !== '') {  // password given
          this.storage.set('basicAuth', btoa(credentials[0] + ':' + password));
        }
      }
      this.api.get('/authorized', (data: any, error) => {
        if (!error) {
          if (data.status === 'Authorization successful') {
            this.loggedIn = true;
            this.levels.forEach(level => {
              this.isLevel[level] = this.levels.indexOf(data.level) >= this.levels.indexOf(level);
              if (this.isLevel.dev) {  // set hasPrediction
                this.hasPrediction = true;
              }
              else {
                this.d.load('modelGroups', () => {
                  this.hasPrediction = this.d.arr.modelGroups.length > 0;
                });
              }
            });
            this.userId = data.user_id;
            resolve(true);
          } else {
            this.loggedIn = false;
            this.storage.remove('basicAuth');
            resolve(false);
          }
        } else {
          this.loggedIn = false;
          this.storage.remove('basicAuth');
          resolve(false);
        }
      });
    });
  }

  logout() {
    this.storage.remove('basicAuth');
    this.loggedIn = false;
    this.levels.forEach(level => {
      this.isLevel[level] = false;
    });
    this.hasPrediction = false;
  }

  // canActivate for Angular routing
  canActivate(route: ActivatedRouteSnapshot = null, state: RouterStateSnapshot = null): Observable<boolean> {
    return new Observable<boolean>(observer => {
      new Promise(resolve => {
        if (this.loggedIn === undefined) {
          this.login().then(res => {
            resolve(res);
          });
        }
        else {
          resolve(this.loggedIn);
        }
      }).then(res => {
        const pathPermission = this.pathPermissions.find(e => e.path.indexOf(route.url[0].path) >= 0);
        // check if level is permitted for path
        const ok = res && (!pathPermission || this.isLevel[pathPermission.permission]);
        observer.next(ok);
        observer.complete();
        if (!ok) {
          this.router.navigate(['/']);
        }
      });
    });
  }

  get isLoggedIn() {
    return this.loggedIn;
  }

  get username() {
    return atob(this.storage.get('basicAuth')).split(':')[0];
  }
}
