/*
 * Copyright 2014-2017 MarkLogic Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var should = require('should');

var testlib    = require('../etc/test-lib.js');
var testconfig = require('../etc/test-config-qa.js');

var marklogic = require('../');

testconfig.manageAdminConnection.user     = "admin";
testconfig.manageAdminConnection.password = "admin";
var adminClient = marklogic.createDatabaseClient(testconfig.manageAdminConnection);
var adminManager = testlib.createManager(adminClient);

var db = marklogic.createDatabaseClient(testconfig.restTemporalConnection);
var dbAdmin = marklogic.createDatabaseClient(testconfig.restAdminConnection);
var dbReader = marklogic.createDatabaseClient(testconfig.restReaderConnection);
var q = marklogic.queryBuilder;

var temporalCollectionName = 'temporalCollectionLsqt'
var updateCollectionName = 'updateCollection';


function validateData(response) {
  for (var i = 0; i < response.length; ++i) {
  // Make sure that system and valid times are what is expected
    //console.log("---------------------------------");
    //console.log(response[i]);

    systemStartTime = response[i].content.System.systemStartTime;
    systemEndTime = response[i].content.System.systemEndTime;
    //console.log("systemStartTime = " + systemStartTime);
    //console.log("systemEndTime = " + systemEndTime);
    
    validStartTime = response[i].content.Valid.validStartTime;
    validEndTime = response[i].content.Valid.validEndTime;
    //console.log("validStartTime = " + validStartTime);
    //console.log("validEndTime = " + validEndTime);


    var quality = response[i].quality;
    //console.log("Quality: " + quality);

    var permissions = response[i].permissions;
    
    if ((validStartTime.indexOf("2003-01-01T00:00:00") !== -1) && (validEndTime.indexOf("2008-12-31T23:59:59") !== -1)) {
      systemStartTime.should.containEql("2011-01-01T00:00:01");
      systemEndTime.should.containEql("9999-12-31T11:59:59Z");

      // This is the updated document
      // Permissions
      permissions.forEach(function(permission) {
        switch(permission['role-name']) {
          case 'app-user':
            permission.capabilities.length.should.equal(1);
            permission.capabilities[0].should.equal('read');
            break;
          case 'app-builder':
            permission.capabilities.length.should.equal(3);
            permission.capabilities.should.containEql('read');
            permission.capabilities.should.containEql('update');
            permission.capabilities.should.containEql('execute');
            break;
        }
      });
    }
    else  if ((validStartTime.indexOf("2001-01-01T00:00:00") !== -1) && (validEndTime.indexOf("2003-01-01T00:00:00") !== -1)) {
      systemStartTime.should.containEql("2011-01-01T00:00:01");
      systemEndTime.should.containEql("9999-12-31T11:59:59Z");

      permissions.forEach(function(permission) {
        switch(permission['role-name']) {
          case 'app-user':
            permission.capabilities.length.should.equal(1);
            permission.capabilities[0].should.equal('read');
            break;
          case 'app-builder':
            permission.capabilities.length.should.equal(2);
            permission.capabilities.should.containEql('read');
            permission.capabilities.should.containEql('update');
            break;
        }
      });
    }

/*****
      Iterator<String>  resCollections = metadataHandle.getCollections().iterator();
      while (resCollections.hasNext()) {
        String collection = resCollections.next();
        System.out.println("Collection = " + collection);
        
        if (!collection.equals(docId) &&
            !collection.equals(updateCollectionName) && 
            !collection.equals(temporalLsqtCollectionName)) {
          assertFalse("Collection not what is expected: " + collection, true);
        }
      }
      
      assertTrue("Properties should be empty", metadataHandle.getProperties().isEmpty());

      assertTrue("Document permissions difference in size value",
          actualPermissions.contains("size:3"));
      
      assertTrue("Document permissions difference in rest-reader permission",
          actualPermissions.contains("rest-reader:[READ]"));
      assertTrue("Document permissions difference in rest-writer permission",
          actualPermissions.contains("rest-writer:[UPDATE]"));
      assertTrue("Document permissions difference in app-user permission",
          (actualPermissions.contains("app-user:[") && actualPermissions.contains("READ") && 
           actualPermissions.contains("UPDATE")));
      assertFalse("Document permissions difference in app-user permission", actualPermissions.contains("EXECUTE"));
      
      assertEquals(quality, 99);
    }           

    if (validStartTime.contains("2001-01-01T00:00:00") && validEndTime.contains("2003-01-01T00:00:00")) {
      assertTrue("System start date check failed", (systemStartTime.contains("2011-01-01T00:00:01")));
      assertTrue("System start date check failed", (systemEndTime.contains("9999-12-31T23:59:59")));
      
      Iterator<String>  resCollections = metadataHandle.getCollections().iterator();
      while (resCollections.hasNext()) {
        String collection = resCollections.next();
        System.out.println("Collection = " + collection);
        
        if (!collection.equals(docId) &&
            !collection.equals(insertCollectionName) && 
            !collection.equals(temporalLsqtCollectionName)) {
          assertFalse("Collection not what is expected: " + collection, true);
        }
      }
      
      assertTrue("Properties should be empty", metadataHandle.getProperties().isEmpty());

      assertTrue("Document permissions difference in size value",
          actualPermissions.contains("size:3"));
      
      assertTrue("Document permissions difference in rest-reader permission",
          actualPermissions.contains("rest-reader:[READ]"));
      assertTrue("Document permissions difference in rest-writer permission",
          actualPermissions.contains("rest-writer:[UPDATE]"));
      assertTrue("Document permissions difference in app-user permission",
          (actualPermissions.contains("app-user:[") && actualPermissions.contains("READ") && 
           actualPermissions.contains("UPDATE") && actualPermissions.contains("EXECUTE")));
      
      assertEquals(quality, 11);
    }  
    
    if (validStartTime.contains("2008-12-31T23:59:59") && validEndTime.contains("2011-12-31T23:59:59")) {         
      // This is the latest document          
      assertTrue("System start date check failed", (systemStartTime.contains("2011-01-01T00:00:01")));
      assertTrue("System start date check failed", (systemEndTime.contains("9999-12-31T23:59:59")));          
      assertTrue("URI should be the doc uri ", record.getUri().equals(docId));

      Iterator<String>  resCollections = metadataHandle.getCollections().iterator();
      while (resCollections.hasNext()) {
        String collection = resCollections.next();
        System.out.println("Collection = " + collection);
        
        if (!collection.equals(docId) &&
            !collection.equals(insertCollectionName) && 
            !collection.equals(temporalLsqtCollectionName) &&
            !collection.equals(latestCollectionName)) {
          assertFalse("Collection not what is expected: " + collection, true);
        }
      }
              
      
      assertTrue("Document permissions difference in size value",
          actualPermissions.contains("size:3"));
      
      assertTrue("Document permissions difference in rest-reader permission",
          actualPermissions.contains("rest-reader:[READ]"));
      assertTrue("Document permissions difference in rest-writer permission",
          actualPermissions.contains("rest-writer:[UPDATE]"));
      assertTrue("Document permissions difference in app-user permission",
          (actualPermissions.contains("app-user:[") && actualPermissions.contains("READ") && 
           actualPermissions.contains("UPDATE") && actualPermissions.contains("EXECUTE")));

      assertEquals(quality, 11);
      
      validateMetadata(metadataHandle);
    }  
    
    if (validStartTime.contains("2001-01-01T00:00:00") && validEndTime.contains("2011-12-31T23:59:59")) {
      assertTrue("System start date check failed", (systemStartTime.contains("2010-01-01T00:00:01")));
      assertTrue("System start date check failed", (systemEndTime.contains("2011-01-01T00:00:01")));

      Iterator<String>  resCollections = metadataHandle.getCollections().iterator();
      while (resCollections.hasNext()) {
        String collection = resCollections.next();
        System.out.println("Collection = " + collection);
        
        if (!collection.equals(docId) &&
            !collection.equals(insertCollectionName) && 
            !collection.equals(temporalLsqtCollectionName)) {
          assertFalse("Collection not what is expected: " + collection, true);
        }
      }         
      
      assertTrue("Properties should be empty", metadataHandle.getProperties().isEmpty());

      assertTrue("Document permissions difference in size value",
          actualPermissions.contains("size:3"));
      
      assertTrue("Document permissions difference in rest-reader permission",
          actualPermissions.contains("rest-reader:[READ]"));
      assertTrue("Document permissions difference in rest-writer permission",
          actualPermissions.contains("rest-writer:[UPDATE]"));
      assertTrue("Document permissions difference in app-user permission",
          (actualPermissions.contains("app-user:[") && actualPermissions.contains("READ") && 
           actualPermissions.contains("UPDATE") && actualPermissions.contains("EXECUTE")));

      assertEquals(quality, 11);
    } 
    ***/  
  }
}








describe('Temporal update lsqt test', function() {
  
  var docuri = 'temporalDoc.json'; 
  var docuri2 = 'nonTemporalDoc.json';
 
  before(function(done) {
   adminManager.put({
      endpoint: '/manage/v2/databases/'+testconfig.testServerName+'/temporal/collections/lsqt/properties?collection=temporalCollectionLsqt',
      body: {
        "lsqt-enabled": true,
        "automation": {
          "enabled": true
        }
      }
    }).result(function(response){done();}, done);
  });

  it('should write the document content name', function(done) {
    db.documents.write({
      uri: docuri,
      collections: ['coll0', 'coll1'],
      temporalCollection: temporalCollectionName,
      contentType: 'application/json',
      quality: 10,
      permissions: [
        {'role-name':'app-user', capabilities:['read']},
        {'role-name':'app-builder', capabilities:['read', 'update']}
      ],
      properties: {prop1:'foo', prop2:25},
      content: {
        'System': {
          'systemStartTime' : "1999-01-01T00:00:00",  // THis value should not matter
          'systemEndTime' : "",
        },
        'Valid': {
          'validStartTime': "2001-01-01T00:00:00",
          'validEndTime': "2011-12-31T23:59:59"
        },
        'Address': "999 Skyway Park",
        'uri': "javaSingleDoc1.json",
        id: 12, 
        name: 'Jason'
      },
      systemTime: '2010-01-01T00:00:00'
    }
    ).result(function(response){done();}, done);
  });


  it('should update the document content name', function(done) {
   db.documents.write({
      uri: docuri,
      collections: [updateCollectionName],
      temporalCollection: temporalCollectionName,
      contentType: 'application/json',
      quality: 10,
      permissions: [
        {'role-name':'app-user', capabilities:['read']},
        {'role-name':'app-builder', capabilities:['read', 'update', 'execute']}
      ],
      properties: {prop1:'foo updated', prop2:50},
      content: {
        'System': {
          'systemStartTime' : "",
          'systemEndTime' : "",
        },
        'Valid': {
          'validStartTime': "2003-01-01T00:00:00",
          'validEndTime': "2008-12-31T23:59:59"
        },
        'Address': "888 Skyway Park",
        'uri': "javaSingleDoc1.json",
        id: 12, 
        name: 'Bourne'
      },
      systemTime: '2011-01-01T00:00:01'
    }).result(function(response){done();}, done);
  });


  it('should read the document content name', function(done) {
    db.documents.read({uris: docuri}).result(function(documents) {
      var document = documents[0];
      document.content.Address.should.equal('999 Skyway Park');
      done();
    }, done);
  });

  it('should read the document content id', function(done) {
    db.documents.read({uris: docuri, categories:['content']}).result(function(documents) {
      var document = documents[0];
      document.content.Valid.validStartTime.should.equal("2008-12-31T23:59:59");
      done();
    }, done);
  });

  it('should read the document quality (metadata) and content', function(done) {
    db.documents.read({uris: docuri, categories:['metadata', 'content']})
    .result(function(documents) {
      var document = documents[0];
      document.quality.should.equal(10);
      document.properties.prop1.should.equal('foo updated');  // properties do not travel with splits
      done();
    }, done);
  });

  it('should read the document collections', function(done) {
    db.documents.read({uris: docuri, categories:['metadata']}).result(function(documents) {
      var document = documents[0];
      var collCount = document.collections.length;
      collCount.should.equal(5);  // Should be coll0, coll1, temporalCollection, docUri and latest
      for (var i=0; i < collCount; i++) {
        var coll = document.collections[i];

        if (document.collections[i] !== temporalCollectionName && document.collections[i] !== 'coll0' &&
            document.collections[i] !== 'coll1' && document.collections[i] !== 'latest' &&
            document.collections[i] !== docuri) {
          //console.log("Invalid Collection: " + coll);
          should.equal(false, true);
        }
      }           
      done();
    }, done);
  });

  it('should read the document permissions', function(done) {
    db.documents.read({uris: docuri, categories:['metadata']}).result(function(documents) {
      var document = documents[0];
      var permissionsCount = 0;
      document.permissions.forEach(function(permission) {
        switch(permission['role-name']) {
          case 'app-user':
            permissionsCount++;
            permission.capabilities.length.should.equal(1);
            permission.capabilities[0].should.equal('read');
            break;
          case 'app-builder':
            permissionsCount++;
            permission.capabilities.length.should.equal(2);
            permission.capabilities.should.containEql('read');
            permission.capabilities.should.containEql('update');
            break;
        }
      });
      permissionsCount.should.equal(2);
      done();
    }, done);
  });

  it('should read multiple documents', function(done) {
    db.documents.read({uris: [docuri], categories:['content']}).result(function(documents) {
      documents[0].content.id.should.equal(12);
      done();
    }, done);
  });

  it('should read multiple documents with an invalid one', function(done) {
    db.documents.read({uris: [docuri, '/not/here/blah.json'], categories:['content']}).result(function(documents) {
      documents[0].content.id.should.equal(12);
      done();
    }, done);
  });


  it('should do collection query: col0', function(done) {
    db.documents.query(
      q.where(
        q.collection('coll0')
        )
      ).result(function(response) {
        response.length.should.equal(3);
        // response[0].content.id.should.equal('0026');
        // response[1].content.id.should.equal('0012');
        done();
      }, done);
  });

  it('should do collection query: col1', function(done) {
    db.documents.query(
      q.where(
        q.collection('coll1')
        )
      ).result(function(response) {
        response.length.should.equal(3);
        // response[0].content.id.should.equal('0026');
        // response[1].content.id.should.equal('0012');
        done();
      }, done);
  });

  it('should do collection query: updateCollection', function(done) {
    db.documents.query(
      q.where(
        q.collection(updateCollectionName)
        )
      ).result(function(response) {
        response.length.should.equal(1);
        // response[0].content.id.should.equal('0026');
        // response[1].content.id.should.equal('0012');
        done();
      }, done);
  });

  it('should do collection query: temporalCollectioLsqt', function(done) {
    db.documents.query(
      q.where(
        q.collection(temporalCollectionName)
        )
      ).result(function(response) {
        response.length.should.equal(4);
        // response[0].content.id.should.equal('0026');
        // response[1].content.id.should.equal('0012');
        done();
      }, done);
  });


  it(('should do collection query: ' + docuri), function(done) {
    db.documents.query(
      q.where(
        q.collection(docuri)
        )
      ).result(function(response) {
        response.length.should.equal(4);
        // response[0].content.id.should.equal('0026');
        // response[1].content.id.should.equal('0012');
        done();
      }, done);
  });

  it('should do collection query: latest', function(done) {
    db.documents.query(
      q.where(
        q.collection('latest')
        )
      ).result(function(response) {
        response.length.should.equal(1);
        // response[0].content.id.should.equal('0026');
        // response[1].content.id.should.equal('0012');
        done();
      }, done);
  });

  it('should do validate data', function(done) {
    db.documents.query(
      q.where(
        q.collection(docuri)
        ).withOptions({categories:['content', 'metadata']})
      ).result(function(response) {
        validateData(response);
        done();
      }, done);
  });

  it('should delete the document', function(done) {
    db.documents.remove({
      uris: [docuri],
      temporalCollection: temporalCollectionName
    }).result(function(document) {

      done();
    }, done);
  });

  it('should read document by uri after delete', function(done) {
    db.documents.read({uris: [docuri], categories:['content']}).result(function(documents) {
      documents[0].content.id.should.equal(12);
      done();
    }, done);
  });

  /*after(function(done) {
   return adminManager.post({
      endpoint: '/manage/v2/databases/' + testconfig.testServerName,
      contentType: 'application/json',
      accept: 'application/json',
      body:   {'operation': 'clear-database'}
    }).result().then(function(response) {
      if (response >= 400) {
        console.log(response);
      } 
      done();
    }, function(err) {
      console.log(err); done();
    },
    done);
  });*/

  after(function(done) {
    dbAdmin.documents.removeAll({
      all: true
    }).
    result(function(response) {
      done();
    }, done);
  });

  /***
  after(function(done) {
   return adminManager.post({
      endpoint: '/manage/v2/databases/' + testconfig.testServerName,
      contentType: 'application/json',
      accept: 'application/json',
      body:   {'operation': 'clear-database'}
    }).result(function(response) {
      return adminManager.put({
        endpoint: '/manage/v2/databases/'+testconfig.testServerName+'/temporal/collections/lsqt/properties?collection=temporalCollectionLsqt',
        body: {
          "lsqt-enabled": true
        }
      }).result();
      done();
    }, done);
  });
***/

/***
  it('should delete the document', function(done) {
    db.documents.remove({
      uri: docuri,
      temporalCollection: temporalCollectionName
    }).result(function(document) {
      // Document by the docUri should exist
      document.exists.should.eql(true);
      done();
    }, done);
  });
***/
});
