import {AbilitiesType, accessState, AccessStore, AnyJson} from "~/types/interfaces";
import {Ability} from "@casl/ability";
import {Store} from "vuex";

/**
 * L'AccessProfile permet de manipuler l'AccessState l'Access qui peuvent
 * être nécessaires pour l'affichage de chacune des pages de l'application
 * (ex: rôles, habilités, ...etc)
 */
export class AccessProfile {
  private accessProfile!: accessState

  private $ability:Ability = {} as Ability
  private store!:Store<any>

  /**
   * Set le store
   * @param {Store<AccessStore>} store
   */
  public setStore (store: AccessStore) {
    this.accessProfile = store.state.profile.access
    this.store = store
  }

  /**
   * Permet de setter le service d'abilités
   * @param ability
   */
  public setAbility(ability: Ability){
    this.$ability = ability
  }

  /**
   * Est-ce que l'utilisateur possède le rôle donné?
   *
   * @param {Array<string>} roles Rôles à tester
   * @return {boolean}
   */
  hasRole (roles: Array<string>|null): boolean {
    if (roles === null) {
      return true
    }

    let hasRole = false
    roles.map((r) => {
      if (this.accessProfile.roles.includes(r)) {
        hasRole = true
      }
    })
    return hasRole
  }

  /**
   * Est-ce que l'utilisateur possède l'abilité
   * @param {Array<AbilitiesType>} abilities abilités à tester
   * @return {boolean}
   */
  hasAbility(abilities:Array<AbilitiesType>|null): boolean{
    if(abilities === null)
      return true;

    let hasAbility= false;
    abilities.map((ability) => {
      if (this.$ability.can(ability.action, ability.subject))
        hasAbility = true;
    });
    return hasAbility;
  }

  /**
   * Retourne vrai si l'utilisateur connecté possède l'un des profiles passés en paramètre
   * @param {Array<string>} profiles : profiles à tester
   * @return {boolean}
   */
  hasProfile(profiles: Array<string>|null): boolean{
    if (null === profiles)
      return true;

    let hasProfile = false;
    profiles.map(async (profile) => {
      if (this.testProfile(profile))
        hasProfile = true;
    });
    return hasProfile;
  }

  /**
   * Factory pour tester le profil d'un utilisateur
   * @param {string} profile : profile à tester
   * @return {boolean}
   */
  testProfile(profile:string): boolean{
    const factory: {[key: string]: boolean} = {
      'admin': this.accessProfile.isAdmin,
      'administratifManager': this.accessProfile.isAdministratifManager,
      'pedagogicManager': this.accessProfile.isPedagogicManager,
      'financialManager': this.accessProfile.isFinancialManager,
      'caMember': this.accessProfile.isCaMember,
      'student': this.accessProfile.isStudent,
      'teacher': this.accessProfile.isTeacher,
      'member': this.accessProfile.isMember,
      'other': this.accessProfile.isOther,
      'guardian': this.accessProfile.isGuardian,
      'payor': this.accessProfile.isPayor,
    }

    if(profile in factory)
      return factory[profile]
    else return false
  }

  /**
   * Est-ce que l'utilisateur possède un compte administrateur
   * @return {boolean}
   */
  isAdminAccount(): boolean{
    return this.accessProfile.isAdminAccess
  }

  /**
   * Retourne l'id de la session en cours
   * @return {boolean}
   */
  getCurrentAccessId(): number{
    return this.accessProfile.switchId ?? this.accessProfile.id
  }

  /**
   * Factory
   *
   * @return {AnyJson} retourne les fonction rendues publiques
   */
  handler (): AnyJson {
    return {
      hasRole: this.hasRole.bind(this),
      hasAbility: this.hasAbility.bind(this),
      hasProfile: this.hasProfile.bind(this),
      isAdminAccount: this.isAdminAccount.bind(this)
    }
  }
}

export const $accessProfile = new AccessProfile()
