import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';

interface IOptions {
  isRole: boolean;
}

const isArray = Array.isArray;

const toArray = (strOrArr: string | string[]) => {
  return isArray(strOrArr) ? strOrArr : [strOrArr];
};

const partInArray = (all: string[] = [], sub: string[] = []) => {
  return !!sub.find(s => all.includes(s));
};

const allInArray = (all: string[] = [], sub: string[] = []) => {
  return !!sub.every(s => all.includes(s));
};

const partNotInArray = (all: string[] = [], sub: string[] = []) => {
  return !!sub.find(s => !all.includes(s));
};

const allNotInArray = (all: string[] = [], sub: string[] = []) => {
  return sub.every(s => !all.includes(s));
};

@Injectable({ providedIn: 'root' })
export class BixiACService {
  private _permissions: string[] = [];
  private _roles: string[] = [];
  private _roles$ = new BehaviorSubject<string[]>([]);
  private _permissions$ = new BehaviorSubject<string[]>([]);

  get roles$() {
    return this._roles$;
  }

  get permissions$() {
    return this._permissions$;
  }

  public ac(data: string | string[], options: IOptions = { isRole: false }): boolean {
    return allInArray(options.isRole ? this._roles : this._permissions, toArray(data));
  }

  public acAny(data: string | string[], options: IOptions = { isRole: false }): boolean {
    return partInArray(options.isRole ? this._roles : this._permissions, toArray(data));
  }

  public ace(data: string | string[], options: IOptions = { isRole: false }): boolean {
    return allNotInArray(options.isRole ? this._roles : this._permissions, toArray(data));
  }

  public aceAny(data: string | string[], options: IOptions = { isRole: false }): boolean {
    return partNotInArray(options.isRole ? this._roles : this._permissions, toArray(data));
  }

  setPermissions(permissions: string | string[]): void {
    this._permissions = toArray(permissions);
    this._permissions$.next(this._permissions);
  }

  setRoles(roles: string | string[]): void {
    this._roles = toArray(roles);
    this._roles$.next(this._roles);
  }

  getPermissions(): string[] {
    return this._permissions || [];
  }

  getRoles(): string[] {
    return this._roles || [];
  }

  clear() {
    this.setPermissions([]);
    this.setRoles([]);
  }
}
