/**
 * @file Fonctions qui gerent l'autorisation des utilisateurs
 * @author ofacklam
 * @memberof GraphQL
 */

import { Tools, GroupSet, GroupCollection } from "./tools";
import { User as UT } from '../../ldap/export/user'

/*
 * There are 7 levels of authorisation
 *  none : doesn't know the group / the user exists
 *  connectedOrOnplatal : knows the group exists, can use TOL
 *  viewer : can see the group
 *  member : part of the group
 *  speaker : allowed to speak for the group
 *  admin : admin of the group
 *  supervisor : allowed to take control of the group
 */

export class AuthorisationModel {
    
    /**
     * @memberof GraphQL
     * @class AuthorisationModel
     * @summary Autorisation des utilisateurs.
     * @classdesc Cette classe contient les méthodes d'autorisation de l'utilisateur dans le 'context'.
     * @arg {string} uid - L'identifiant de l'utilisateur.
     */
    constructor(uid: string) {
        this.uid = uid;
    }

    /**
     * @memberof GraphQL
     * @summary Fonction qui crée une nouvelle instance de AuthorisationModel et charge les données
     * @arg {string} uid - Identifiant de l'utilisateur.
     * @returns {Promise<AuthorisationModel>} Renvoie un nouveau AuthorisationModel avec cet utilisateur
     * @async
     * @static
     */
    static async create(uid: string): Promise<AuthorisationModel> {
        let model = new AuthorisationModel(uid);
        
        if(model.isAuthenticated()) {
            await model.fetchData();
        }

        return model;
    }

    protected uid: string;
    protected viewerOf: GroupCollection;
    protected memberOf: GroupCollection;
    protected speakerOf: GroupCollection;
    protected adminOf: GroupCollection;
    protected supervisorOf: GroupCollection;

    static PUBLICUSER = "public_user";
    static ONPLATALUSER = "public_onplatal_user";

    /**
     * @memberof GraphQL.AuthorisationModel#
     * @summary Fonction qui recupere toutes les données pour populer les champs a partir de l'uid.
     * @async
     */
    async fetchData(): Promise<void> {
        let data = await UT.peek(this.uid);

        this.viewerOf = await Tools.viewerOf(data);
        this.memberOf = await Tools.memberOf(data);
        this.speakerOf = await Tools.viewerOf(data);
        this.adminOf = await Tools.adminOf(data);
        this.supervisorOf = await Tools.supervisorOf(data);
    }

    /**
     * @memberof GraphQL.AuthorisationModel#
     * @summary Fonction qui renvoit si l'utilisateur est connecté ou on-platal
     * @return {boolean} Renvoie true si l'utilisateur est connecté ou on-platal
     */
    isConnectedOrOnplatal(): boolean {
        return (this.uid != AuthorisationModel.PUBLICUSER);
    }

    /**
     * @memberof GraphQL.AuthorisationModel#
     * @summary Fonction qui renvoit si l'utilisateur est authentifié
     * @return {boolean} Renvoie true si l'utilisateur est authentifié
     */
    isAuthenticated(): boolean {
        return (this.uid != AuthorisationModel.PUBLICUSER && this.uid != AuthorisationModel.ONPLATALUSER);
    }

    /**
     * @memberof GraphQL.AuthorisationModel#
     * @summary Fonction qui renvoit si l'utilisateur est viewer du groupe.
     * @arg {string} gid - Identifiant du groupe.
     * @return {boolean} Renvoie true si l'utilisateur est viewer du groupe.
     */
    isViewer(gid: string): boolean {
        //ensure uid is valid !!!!!!!!
        if (this.isAuthenticated()) {
            let groups = this.viewerOf;
            return (groups.simpleGroups.has(gid) || groups.metaGroups.has(gid));
        }
        return false;
    }

    /**
     * @memberof GraphQL.AuthorisationModel#
     * @summary Fonction qui renvoit si l'utilisateur est membre du groupe.
     * @arg {string} gid - Identifiant du groupe.
     * @return {boolean} Renvoie true si l'utilisateur est membre du groupe.
     */
    isMember(gid: string): boolean {
        //ensure uid is valid !!!!!!!!
        if (this.isAuthenticated()) {
            let groups = this.memberOf;
            return (groups.simpleGroups.has(gid) || groups.metaGroups.has(gid));
        }
        return false;
    }

    /**
     * @memberof GraphQL.AuthorisationModel#
     * @summary Fonction qui renvoit si l'utilisateur est membre d'au moins un de ces groupes.
     * @arg {GroupSet} groups - Ensemble de groupes.
     * @return {boolean} Renvoie true si l'utilisateur est membre d'un des groupes
     */
    isMemberOr(groups: GroupSet): boolean {
        //ensure uid is valid !!!!!!!!
        if (this.isAuthenticated()) {
            let member = this.memberOf;

            for (let gid of groups) {
                if (member.simpleGroups.has(gid) || member.metaGroups.has(gid)) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * @memberof GraphQL.AuthorisationModel#
     * @summary Fonction qui renvoit si l'utilisateur est speaker du groupe.
     * @arg {string} gid - Identifiant du groupe.
     * @return {boolean} Renvoie true si l'utilisateur est speaker du groupe.
     */
    isSpeaker(gid: string): boolean {
        //ensure uid is valid !!!!!!!!
        if (this.isAuthenticated()) {
            let groups = this.speakerOf;
            return (groups.simpleGroups.has(gid) || groups.metaGroups.has(gid));
        }
        return false;
    }

    /**
     * @memberof GraphQL.AuthorisationModel#
     * @summary Fonction qui renvoit si l'utilisateur est admin du groupe.
     * @arg {string} gid - Identifiant du groupe.
     * @return {boolean} Renvoie true si l'utilisateur est admin du groupe.
     */
    isAdmin(gid: string): boolean {
        //ensure uid is valid !!!!!!!!
        if (this.isAuthenticated()) {
            let groups = this.adminOf;
            return (groups.simpleGroups.has(gid) || groups.metaGroups.has(gid));
        }
        return false;
    }

    /**
     * @memberof GraphQL.AuthorisationModel#
     * @summary Fonction qui renvoit si l'utilisateur est supervisor du groupe.
     * @arg {string} gid - Identifiant du groupe.
     * @return {boolean} Renvoie true si l'utilisateur est supervisor du groupe.
     */
    isSupervisor(gid: string): boolean {
        //ensure uid is valid !!!!!!!!
        if (this.isAuthenticated()) {
            let groups = this.supervisorOf;
            return (groups.simpleGroups.has(gid) || groups.metaGroups.has(gid));
        }
        return false;
    }

}