/**
 * @file Implémentation des requêtes GraphQL.
 * @author akka vodol
*/
import { request } from 'https';
import _ from 'lodash';
import { assertBinaryExpression } from 'babel-types';
import knex from '../../db/knex_router';

import * as connectors from './connectors/connectors';
import * as list_selectors from './connectors/list_selectors';
import * as authentifiers from './connectors/authentifiers';

// nouveau test

/** 
 * @description Résolveurs des différentes requêtes GraphQL
*/

function ChevalierError(err){
    this.returned_error = err;
    this.name = "chevalier error";
    this.message = "Error encountered while running ldap access code : " + err.message;
    this.toString = () => this.message;
}


export const resolvers = {
    // @rights user
    Query: {

        // group queries

        allGroups: async function(obj, args, context){
            let user = await authentifiers.anonymous(context.user);
            return user && connectors.getAllVisibleGroups(user);
        },

        allSimpleGroups: async function (obj, args, context){
            let user = await authentifiers.anonymous(context.user);
            return user && connectors.getAllVisibleSimpleGroups(user);
        },

        group: async function(obj, args, context){
            let user = await authentifiers.anonymous(context.user);
            return user && connectors.getGroupIfVisible(user, args.uid);
        },

        simpleGroup: async function(obj, args, context){
            let user = await authentifiers.anonymous(context.user);
            return user && connectors.getSimpleGroupIfVisible(user, args.uid);
        },
        metaGroup: async function(obj, args, context){
            let user = await authentifiers.anonymous(context.user);
            return user && connectors.getMetaGroupIfVisible(user, args.uid);
        },

        /*
         * Message queries.
         */

        allAnnouncements: function(obj, args, context) {
            return knex.select().from("announcements");
        },

        allEvents: function(obj, args, context) {
            return knex.select().from("events");
        },


        // user queries

        user: async function(obj, args, context){
            let user = await authentifiers.anonymous(context.user);
            return user && connectors.getUser(user,args.uid);
        },

        searchTOL: (obj, args, context) => {
            console.log("Searching TOL for",args);
            const result = connectors.utilisateur.repliquerTOLdesIds({
                givenName: args.givenName,
                lastName: args.lastName,
                nickname: args.nickname,
                nationality: args.nationality,
                school: args.school,
                promotion: args.promotion,
                groups: args.groups,
                studies: args.studies,
                sport: args.sport,
                phone: args.phone,
                mail: args.mail,
                adress: args.adress,
                ip: args.ip
            });
            return result;
        },

        // viewer queries

        // member queries

        allMembers : async function(obj, args, context){
            let user = await authentifiers.member(context.user, args.from);
            return user && connectors.getGroupMemberUsers(context.user, obj.groupUID);
        },

        // speaker queries

        allRequests: async function(obj, args, context){
            let res = [];
            let user = authentifiers.admin(context.user, args.from);
            if(user){
                res = res.concat(await connectors.getUserJoinGroupRequests(user, args.from));
            }
            user = user || authentifiers.speaker(user, args.from);
            if(user){
                res = res.concat(await connectors.getGroupJoinEventRequests(user, args.from));
                res = res.concat(await connectors.getYourGroupHostEventRequests(user, args.from));
            }
            return res;
        },

        test: async function(obj, args, context){
            return connectors.getSimpleGroup(context.user, "br");
        }
    },


    Request : {
        __resolveType : function(obj){
            return obj.type;
        }
    },

    // @rights admin(obj.groupUID)
    UserJoinGroup: {
        user : (obj, args, context) => {
            return connectors.getUser(context.user, obj.useruid);
            /*return connectors.getUser(context.user, "quentin.gendre");
            if(obj.useruid === "anatole.romon"){
                return connectors.getUser(context.user, "anatole.romon").then(res => {
                    return connectors.getUser(context.user, "quentin.gendre");
                });
            }else{
                return new Promise( (resolve, reject) => {
                    resolve({givenName : "patrick"});
                });
            }*/
        }
    },

    // @rights speaker(obj.groupUID)
    GroupJoinEvent : {
        event: (obj, args, context) => {
            return connectors.getEvent(context.user, obj.eventuid);
        },
        groupWantingToJoin: (obj, args, context) => {
            return connectors.getGroup(context.user, obj.senderuid);
        }
    },

    // @rights speaker(obj.groupUID)
    YourGroupHostEvent : {
        event: (obj, args, context) => {
            return connectors.getEvent(context.user, obj.eventuid);
        },
        sender: (obj, args, context) => {
            return connectors.getGroup(context.user, obj.senderuid);
        }
    },

    // @rights user
    User : {
        groups : (obj, args, context) => {
            let result = Promise.all(obj.groups.map((grid) => {
                return connectors.getSimpleGroup(context.user,grid);
            }));

            return result.then(groups => {
                return _.filter(groups,(o) => !_.isUndefined(o));
            });
        },

    },

    // @rights user
    Mutation: {

        // Superviser mutations

        takeAdminRights : async function(obj, args, context){
            let user = await authentifiers.superviser(context.user, args.from);
            return user && await connectors.takeAdminRights(user, args.from, user.justification);
        },

        releaseAdminRights : async function(obj, args, context){
            let user = await authentifiers.superviser(user, args.from);
            return user && await connectors.releaseAdminRights(user, args.from, user.justification);
        },

        // Admin mutations

        createSubgroup: async function (obj, args, context){
            let user = authentifiers.admin(context.user, args.from);
            return user && connectors.createSubgroup(user, args);
        },

    },


    Message: {

        __resolveType: function(obj) {
            return obj.type;

        }
    },

    Announcement: {
        forEvent : function(obj, args, context){
            // le champ is_announcement n'existe que sur les Events
            // une ligne de la bdd events peut résoudre comme évènement ou comme annonce
            if(obj.is_announcement) 
                return obj;
            else
                return null;
        },

        authors: async function (obj, args, context){
            return connectors.getMessageGroupAuthors(context.user, obj.id);
        },

        recipients: async function (obj, args, context){
            return connectors.getMessageGroupRecipients(context.user, obj.id);
        }
    },

    Event: {

        startTime : function(obj){
            return obj.start_time;
        },

        endTime : function(obj){
            return obj.end_time;
        },

        asAnnouncement : function(obj, args, context){
            // le champ is_announcement indique si il existe une annonce qui va avec l'évènement
            // une ligne de la bdd events peut résoudre comme évènement ou comme annonce
            if(obj.is_announcement) 
                return obj;
            else
                return null;
        },

        authors: async function (obj, args, context){
            return connectors.getMessageGroupAuthors(context.user, obj.id);
        },

        recipients: async function (obj, args, context){
            return connectors.getMessageGroupRecipients(context.user, obj.id);
        }
    },

    PrivatePost : {

        authors: async function(obj, args, context){
            return connectors.getUser(context.user, obj.author_uid, obj.author_db);
            
        },

        recipients: async function(obj, args, context){
            return connectors.getGroup(context.user, obj.recipient_uid);
            
        }
    },

    Question : {

        authors: async function(obj, args, context){
            return connectors.getUser(context.user, obj.author_uid, obj.author_db);
        },

        recipients: async function(obj, args, context){
            return connectors.getGroup(context.user, obj.recipient_uid);
        },

        forAnswer: function(obj, args, context){
            return obj.for_answer;
        }
    },

    Answer : {

        authors: async function(obj, args, context){
            return connectors.getGroup(context.user, obj.author_uid);
        },

        recipients: async function(obj, args, context){
            return connectors.getGroup(context.user, obj.recipient_uid);
        },

        forQuestion: function(obj, args, context){
            return obj.for_question;
        }
    },

    // @rights viewer(obj.uid)
    Group: {
        __resolveType: async (obj) => {
            
            switch(obj.type) {
            case "simple":
                return "SimpleGroup";
            case "meta":
                return "MetaGroup";
            }
        }
    },

    // @rights viewer(obj.uid)
    SimpleGroup: {
        
        admins: async function(obj, args, context){
            let user = await authentifiers.member(context.user, obj.uid);
            return await user.ldap_access.listMembers(context.user,obj.uid);
        },

        members: async function(obj, args, context){
            let user = await authentifiers.member(context.user, obj.uid);
            return user.ldap_access.listMembers(context.user,obj.uid);
        },

        likers: async function(obj, args, context){
            return connectors.utilisateur.listMembers(context.user,obj.uid);
        }, 

        privatePosts: async function(obj, args, context){
            let user = await authentifiers.member(context.user, obj.uid);
            return user && connectors.receivedPrivatePosts(user, obj.uid);
        }, 

        questions: async function(obj, args, context){
            let user = await authentifiers.member(context.user, obj.uid);
            return user && connectors.receivedQuestions(user, obj.uid);
        }, 

        answers: async function(obj, args, context){
            let user = await authentifiers.member(context.user, obj.uid);
            return user && connectors.receivedAnswers(user, obj.uid);
        }
    },

    // @rights viewer(obj.uid)
    MetaGroup: {
        members: (obj, args, context) => {
        }, 

        privatePosts: async function(obj, args, context){
            let user = await authentifiers.member(context.user, obj.uid);
            return user && connectors.receivedPrivatePosts(user, obj.uid);
        }, 

        questions: async function(obj, args, context){
            let user = await authentifiers.member(context.user, obj.uid);
            return user && connectors.receivedQuestions(user, obj.uid);
        }, 

        answers: async function(obj, args, context){
            let user = await authentifiers.member(context.user, obj.uid);
            return user && connectors.receivedAnswers(user, obj.uid);
        }
    }
};