import {
  graphql,
  GraphQLSchema,
  GraphQLID,
  GraphQLObjectType,
  GraphQLString,
  GraphQLList,
  GraphQLNonNull
} from 'graphql';

import Note from './note'

/**
 * generate projection object for mongoose
 * @param  {Object} fieldASTs
 * @return {Project}
 */
function getProjection (fieldASTs) {
  return fieldASTs.selectionSet.selections.reduce((projections, selection) => {
    projections[selection.name.value] = 1;

    return projections;
  }, {});
}

const NoteType = new GraphQLObjectType({
  name: 'Note',
  fields:()=> ({
    id: {
      type: new GraphQLNonNull(GraphQLString)
    },
    timestamp: {
      type: GraphQLString
    },
    title: {
      type: GraphQLString
    },
    description: {
      type: GraphQLString
    },
    tags: {
      type: new GraphQLList(GraphQLString)
    },
    file_path: {
      type: GraphQLString
    }
  })
})

const NoteQuery = new GraphQLObjectType({
  name: 'NoteQuery',
  fields: {
    // Query a single note
    note: {
      type: NoteType,
      args: {
        id: {
          type: GraphQLString
        },
        title: {
          type: GraphQLString
        },
        file_path: {
          type: GraphQLString
        }
      },
      resolve(parent, {id, title, file_path}, {fieldASTs}) {
        // Obtain only needed fields from mongoose
        var projections = getProjection(fieldASTs[0]);

        if(id) return Note.findById(id, projections)
        else if(title) return Note.findOne({title:title},projections)
        else if(file_path) return Note.findOne({file_path:file_path},projections)
        else return Note.findOne({},projections)

      }
    },
    // Query a list of notes satsfying some conditions outlined in args
    notes: {
      type: new GraphQLList(NoteType),
      args: {
        ids: {
          type: new GraphQLList(GraphQLString)
        },
        tags: {
          type: new GraphQLList(GraphQLString)
        }
      },
      resolve(parent, {ids, tags}, {fieldASTs}) {
        var projections = getProjection(fieldASTs[0]);

        if(ids) return Note.find({'_id':{$in:ids}}, projections)
        else if(tags) return Note.find({'tags':{$in:tags}}, projections)
        else return Note.find({}, projections)
      }
    }
  }
})

const NoteMutation = new GraphQLObjectType({
  name: 'NoteMutation',
  fields: {
    createNote: {
      type: NoteType,
      args: {
        title: {
          type: GraphQLString
        },
        description: {
          type: GraphQLString
        },
        tags: {
          type: new GraphQLList(GraphQLString)
        },
        file_path: {
          type: GraphQLString
        }
      },
      resolve(parent, noteobj) {
        noteobj.timestamp = Date()
        let note = new Note(noteobj)

        return note.save()
      }
    }
  }
})


export var Schema = new GraphQLSchema({
  query: NoteQuery,
  mutation: NoteMutation
});

@@ -112,16 +112,34 @@
 LNonNull
+,%0A  GraphQLBoolean
 %0A%7D from 
@@ -2793,32 +2793,269 @@
 .save()%0A      %7D%0A
+    %7D,%0A    // @return: The removed Note%0A    removeNote: %7B%0A      type: NoteType,%0A      args: %7B%0A        id: %7B%0A          type: GraphQLString%0A        %7D%0A      %7D,%0A      resolve(parent, %7Bid%7D) %7B%0A        return Note.findByIdAndRemove(id)%0A      %7D%0A
     %7D%0A  %7D%0A%7D)%0A%0A%0Ae

Implement crremoveNote