'use strict';

var q = require('q');

var logger = require('../../../utils/Logger').loggers.get('db');
var cbConnection = require('./CouchbaseConnection');
var UtilDocumentId = require('../../../../shared/utils/UtilDocumentId');
var cbUtil = require('./CouchbaseUtil');
var cbBucket;
var async = require('async');

/**
* 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();

    var bucketName = cbConnection.getConfig(connectionName).bucket;

    if (!documentId) {
        // 10968: if no documentId is passed in, there is no document to check for so resolve as false
        deferred.resolve(false);
    } else {
        // return only the documentId because we only need to check that the document exists, we don't need the data

        var statement = "SELECT `" + bucketName + "`.documentId FROM `" + bucketName + "` " +
            "WHERE documentId = $1 ";

        if (options && options.excludeDeleted){
          statement += ' AND systemHeader.currentVersion = true ';
          statement += " AND (systemHeader.deleted = false OR systemHeader.deleted IS MISSING) ";
        }

        var query = cbUtil.getN1QlQuery(statement);
        cbBucket = cbConnection.getBucket(connectionName);
        cbBucket.query(query, [documentId], function(queryErr, results) {
            if (queryErr) {
                deferred.reject(new Error("Error checking for duplicate: " + queryErr.message));
            } else {
                var result = results.length !== 0;
                deferred.resolve(result);
            }
        });
    }

    return deferred.promise;
}

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

    cbBucket = cbConnection.getBucket(connectionName);
    cbBucket.insert(docUUId, document, function (err, res) {
        if (err) {
            deferred.reject(err);
        } else {
            cbBucket.get(docUUId, function (err, result) {
                if(err) {
                    deferred.reject("Error in getting inserted document: " + document.documentId);
                } else {
                    logger.info("Inserted document: " + document.documentId);
                    var savedRecord = result.value;
                    if (savedRecord && savedRecord.documentId) {
                        logger.info("Inserted document: " + savedRecord.documentId);
                        // the insert operation returns an array of documents,
                        // because we're only inserting one we can return the first doc
                        deferred.resolve(savedRecord);
                    } else {
                        var msg = "Invalid saved record returned by insert operation";
                        logger.error(msg);
                        deferred.reject(msg);
                    }
                }
            });
        }
    });

    return deferred.promise;
}

function getDocumentAndIndexId(document){
    return document.documentId;
}

function insert(documents, connectionName){
    var deferred = q.defer();
    var results = [];
    async.mapSeries(documents, function (doc, next){
        const casId = doc.systemHeader.versionId ? doc.systemHeader.versionId : doc.documentId;
        doInsert(casId, doc, connectionName).then(function(result){
            results.push(result);
            next();
        }, function(error){
            deferred.reject(error);
        });

    }, function(err) {
        if (err){
            deferred.reject(err);
        }
        else{
            deferred.resolve(results[0]);
        }
    });

    return deferred.promise;
}

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

    var cbBucket = cbConnection.getBucket(connectionName);
    var bucketName = cbConnection.getConfig(connectionName).bucket;

    var statement = "UPDATE `" + bucketName + "` ";
    statement += "SET systemHeader.currentVersion = false";

    statement += " WHERE documentId = '" + documentId +
      "' AND systemHeader.currentVersion = true AND systemHeader.deleted = true";

    var query = cbUtil.getN1QlQuery(statement);
    cbBucket.query(query, function(err, updatedDoc) {
      var errorMsg = "Error updating deleted document." + documentId + " - " + err;
      if (err) {
        errorMsg += err;
        logger.error(errorMsg);
        deferred.reject(new Error(errorMsg));
      } else {
        var searchStatement = "SELECT ft.*, meta(ft).id as _id FROM `" + bucketName + "` ft WHERE " +
          "documentId = '" + documentId + "' AND systemHeader.currentVersion = false " +
          "AND systemHeader.deleted = true";
        query = cbUtil.getN1QlQuery(searchStatement);
        cbBucket.query(query, function(err, docs) {
          if (err) {
            errorMsg += err;
            logger.error(errorMsg);
            deferred.reject(new Error(errorMsg));
          } else {
            var searchStatement = "SELECT ft.*, meta(ft).id as _id FROM `" + bucketName + "` ft WHERE " +
              "documentId = '" + documentId + "' AND systemHeader.currentVersion = false " +
              "AND systemHeader.deleted = true";
            query = cbUtil.getN1QlQuery(searchStatement);
            cbBucket.query(query, function(err, docs) {
              if (err) {
                deferred.reject(err);
              } else {
                deferred.resolve(docs[0]);
              }
            });
          }
        });
      }
    });


  return deferred.promise;

}
module.exports = {
    insert: insert,

    documentExists: documentExists,

    getDocumentAndIndexId: getDocumentAndIndexId,

    updateDeletedDocument: updateDeletedDocument
};
