/**
 * @file Fonctions qui implémentent les requetes relatives aux utilisateurs
 * @author ofacklam
 * @memberof GraphQL
 */

import { User } from "../resolvers/users";
import { User as UT, userData } from "../../ldap/export/user"
import { searchTOLArgs, editProfileArgs } from "../typeDefs/queries";
import { ApolloError } from "apollo-server-core";

export class UserModel {

    /**
     * @memberof GraphQL
     * @class UserModel
     * @summary Requetes relatives aux utilisateurs.
     * @classdesc Cette classe contient les méthodes implémentant les requetes relatives aux utilisateurs.
     * @arg {string} contextUser - L'identifiant de l'utilisateur du 'context'
     */
    constructor(contextUser: string) {
        this.contextUser = contextUser;
    }

    protected contextUser: string;

    /**
     * @memberof GraphQL.UserModel#
     * @function getUser
     * @summary Fonction qui renvoit un utilisateur donné.
     * @arg {string} uid - Identifiant demandé.
     * @return {Promise(User)} Renvoie l'utilisateur dont l'identifiant est 'uid'
     * @async
     * @rights connectedOrOnplatal
     */
    async getUser(uid: string): Promise<User> {
        return User.tryCreate(uid);
    }

    /**
     * @memberof GraphQL.UserModel#
     * @function searchTOL
     * @summary Fonction qui recherche dans le TOL
     * @arg {searchTOLArgs} args - les données de recherche
     * @return {Promise(User[])} Renvoie une liste d'utilisateurs
     * @async
     * @rights connectedOrOnplatal
     */
    async searchTOL(args: searchTOLArgs): Promise<User[]> {
        const searchData: userData = {
            givenName: args.givenName,
            lastName: args.lastName,
            nickname: args.nickname,
            nationality: args.nationality,
            promotion: args.promotion,
            groups: args.groups,
            sport: args.sport,
            phone: args.phone,
            mail: args.mail,
            address: args.addresses[0],
            ips: args.ips
        }
        const userList = await UT.search(searchData);
        return userList.map((uid) => new User(uid));
    }

    /**
     * @memberof GraphQL.UserModel#
     * @function editProfile
     * @summary Fonction qui modifie le profil et renvoie l'utilisateur
     * @arg {editProfileArgs} args - les données a modifier 
     * @return {Promise(User)} Renvoie l'utilisateur mis a jour
     * @async
     * @rights authentified
     */
    async editProfile(args: editProfileArgs): Promise<User> {
        let data = await UT.peek(this.contextUser);

        //Modify some fields, keep the others
        let editArgs: userData = {
            uid: data.uid,
            groups: data.groups,
            groupsIsAdmin: data.groupsIsAdmin,
            password: data.password,
            givenName: data.givenName,
            lastName: data.lastName,
            nickname: args.nickname, // <- this field is modified by user
            promotion: data.promotion,
            photo: data.photo,
            birthdate: data.birthdate,
            nationality: data.nationality,
            phone: args.phone, // <- this field is modified
            address: data.address, // WTF why can't this be changed ????
            mail: args.mail, // <- this field is modified
            ips: data.ips,
            directory: data.directory,
            login: data.login,
            readPerm: data.readPerm,
            writePerm: data.writePerm,
            forlifes: data.forlifes,
            sport: data.sport
        };

        if(await UT.edit(editArgs)) {
            return new User(data.uid);
        }
        else {
            throw new ApolloError("Edit failed");
        }
    }

}