'use strict';

var q = require("q");
var MongoConnection = require('./MongoConnection');
var logger = require('../../../utils/Logger').loggers.get('db');
var ObjectID = require('mongodb').ObjectID;

/**
 * local function to check whether the document exists. This should not be exposed outside this module so that it doesn't provide
 * access to documents with no keys
 */
function documentExists(documentId, connectionName, options) {
    var deferred = q.defer();

    if (!documentId) {
        // 10968: if no documentId is passed in, there is no document to check for so resolve as false
        deferred.resolve(false);
    } else {

        MongoConnection.getCollection(function (err, collection) {
            if (err) {
                logger.error(err);
                deferred.reject(err);
            } else {
                // return only the documentId because we only need to check that the document exists, we don't need the data
                var queryProjection = {
                    "documentId": 1
                };

                // don't include a check for currentVersion because we want this to return true if there is
                // any version of the document matching the documentId
                var documentQuery = {
                  $and: [{"documentId": documentId}]
                };

                if (options && options.excludeDeleted){
                  documentQuery.$and.push({"systemHeader.currentVersion": true});
                  //Filter out deleted documents
                  var unDeletedQuery = {"$or": [
                      {"systemHeader.deleted": false},
                      {"systemHeader.deleted": {$exists: false}}
                    ]};
                  documentQuery["$and"].push(unDeletedQuery);
                }
                collection.findOne(documentQuery, queryProjection, function (queryErr, doc) {
                    if (queryErr) {
                        deferred.reject(new Error("Error checking for duplicate: " + queryErr.message));
                    } else {
                        // return true if document exists
                        var result = doc ? true : false;
                        deferred.resolve(result);
                    }
                });
            }
        });

    }

    return deferred.promise;
}


function insert(document, connectionName){
    var deferred = q.defer();

    MongoConnection.getCollection(function (err, collection) {
        if (err) {
            logger.error(err);
            deferred.reject(err);
        } else {

            var options = {
                w: 1 // ensure a safe write
            };

            collection.insertMany(document, options, function (err, result) {
                if (err) {
                    deferred.reject(err);
                } else {
                    deferred.resolve(result.ops[0]);
                }
            });
        }
    }, connectionName);

    return deferred.promise;
}

function getDocumentAndIndexId(document){
    var _id = new ObjectID();
    document._id = _id;
    return _id.toHexString();
}

function updateDeletedDocument(documentId, connectionName){
    var deferred = q.defer();


    MongoConnection.getCollection(function (err, collection) {
      if (err) {
        var errorMsg = "Error creating collection to updateDeletedDocument: " + err;
        logger.error(errorMsg);
        deferred.reject(new Error(errorMsg));
      } else {

        var documentQuery = {
          $and: [{"documentId": documentId}]
        };
        documentQuery.$and.push({"systemHeader.currentVersion": true});
        documentQuery.$and.push({"systemHeader.deleted": true});

        var update = {
          $set: {'systemHeader.currentVersion': false}
        };

        var options = {};
        options.returnOriginal = false;

        // Use findOneAndUpdate function to find document and update it in one atomic operation
        collection.findOneAndUpdate(documentQuery, update, options,
          function(err, results) {
            var errorMsg = "Error updating deleted document." + documentId ;
            if(err) {
              errorMsg += err;
              logger.error(errorMsg);
              deferred.reject(new Error(errorMsg));
            } else if (results) {
              deferred.resolve(results.value);
            } else {
              errorMsg += err;
              logger.error(errorMsg);
              deferred.reject(new Error(errorMsg));
            }
          });
      }
    }, connectionName);


    return deferred.promise;

}

module.exports = {
    insert: insert,

    documentExists: documentExists,

    getDocumentAndIndexId: getDocumentAndIndexId,

    updateDeletedDocument: updateDeletedDocument
};
