// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

var vanadium = require('../..');
var test = require('prova');
var Deferred = require('../../src/lib/deferred');
var serve = require('./serve');
var access = vanadium.security.access;
var permissionsAuthorizer = vanadium.security.access.permissionsAuthorizer;
var allowEveryoneAuthorizer = vanadium.security.access.allowEveryoneAuthorizer;

var service = {
  call: function(ctx, serverCall, arg) {
    return Promise.resolve(1);
  }
};

function createPromiseDispatcher(authorizer, tags) {
  function auth(ctx, call) {
    if (call.method === '__Signature') {
      return null;
    }
    return authorizer(ctx, call);
  }
  var desc = {
    methods: [
      {
        name: 'Call',
        tags: tags
      }
    ]
  };
  service._serviceDescription = desc;
  return function callbackDispatcher(suffix) {
    return {
      service: service,
      authorizer: auth,
    };
  };
}


function testErrorCase(assert, authorizer, tags, isPromise) {
  serve({
    name: 'authorizerTestService',
    autoBind: false,
    dispatcher: isPromise ?
      createPromiseDispatcher(authorizer, tags) :
      createCallbackDispatcher(authorizer, tags)
  }, function(err, res) {
    if (err) {
      return assert.end(err);
    }
    var client = res.runtime.getClient();
    var ctx = res.runtime.getContext();
    client.bindTo(ctx, 'authorizerTestService/auth').then(function(service) {
      service.call(ctx, 'foo').then(function(value) {
        assert.error(new Error('call should not have succeeded. res:' + value));
        res.end(assert);
      }).catch(function(err) {
        assert.ok(err);
        res.end(assert);
      });
    }, function(err) {
      assert.error(err);
      res.end(assert);
    });
  });
}

test('Test errors are properly returned',
function(assert) {
  testErrorCase(assert, function (ctx, call) {
    var def = new Deferred();
    function reject() {
      def.reject(new Error('unauthorized'));
    }
    setTimeout(reject, 0);
    return def.promise;
  }, [], true);
});

function createCallbackDispatcher(authorizer, tags) {
  function auth(ctx, call, cb) {
    if (call.method === '__Signature') {
      cb(null);
    }
    authorizer(ctx, call, cb);
  }
  var desc = {
    methods: [
      {
        name: 'Call',
        tags: tags
      }
    ]
  };
  service._serviceDescription = desc;
  return function callbackDispatcher(suffix) {
    return {
      service: service,
      authorizer: auth,
    };
  };
}

function testSuccessCase(assert, authorizer, tags, isPromise) {
  serve({
    name: 'authorizerTestService',
    autoBind: false,
    dispatcher: isPromise ?
      createPromiseDispatcher(authorizer, tags) :
      createCallbackDispatcher(authorizer, tags)
  }, function(err, res) {
    if (err) {
      return assert.end(err);
    }
    var client = res.runtime.getClient();
    var ctx = res.runtime.getContext();
    client.bindTo(ctx, 'authorizerTestService/auth').then(function(service) {
      return service.call(ctx, 'foo');
    }).then(function() {
      assert.pass('RPC resolved');
      res.end(assert);
    }).catch(function(err) {
      assert.fail('RPC rejected with error:' + err.toString());
      res.end(assert);
    });
  });
}


test('Test successes are handled', function(assert) {
  testSuccessCase(assert, function (ctx, call, cb) {
    process.nextTick(cb.bind(null, null));
  });
});

test('Test proper context is passed to authorizer', function(assert) {
  var defaultBlessingRegex = require('./default-blessing-regex');

  testSuccessCase(assert, function (ctx, call, cb) {
    if (!defaultBlessingRegex.test(call.remoteBlessingStrings[0])) {
      return cb(new Error('unknown remote blessings ' +
        call.remoteBlessingStrings));
    } else if (!defaultBlessingRegex.test(call.localBlessingStrings[0])) {
      cb(new Error('unknown local blessings ' + call.localBlessingStrings));
    } else if (call.method !== 'call') {
      return cb(new Error('wrong method ' + call.method));
    } else if (call.suffix !== 'auth') {
      return cb(new Error('wrong suffix ' + call.suffix));
    }
    // TODO(bjornick): Fix the endpoint format
    // } else if (call.remoteEndpoint === endpoint ||
    //     !call.remoteEndpoint) {
    //   return new Error('bad endpoint ' + call.remoteEndpoint);
    // } else if  (call.localEndpoint !== endpoint ||
    //     !call.localEndpoint) {
    //   return new Error('bad endpoint ' + call.localEndpoint);
    // }

    cb();
  });
});

test('Test passing in labels', function(assert) {
  testSuccessCase(assert, function(ctx, call, cb) {
    if (call.methodTags[0] !== 'foo') {
      return cb(new Error('wrong label ' + call.label));
    }
    return cb();
  }, ['foo']);
});

var perms = {
  foo: {
    in: ['...']
  },
  bar: {}
};
var tagPermsAuthorizer = permissionsAuthorizer(perms, access.Tag);


test('Test permissionsAuthorizer (public key) - success', function(assert) {
  var tagBar = new access.Tag('Bar');

  // Passes because we reuse the same public key, despite the tag not being ok.
  testSuccessCase(assert, tagPermsAuthorizer, [tagBar], true);
});

test('Test permissionsAuthorizer (tag) - success', function(assert) {
  var tagFoo = new access.Tag('Foo');

  function diffPublicKeyPermsAuthorizer(ctx, call) {
    // get rid of public key, just for this example
    call.remoteBlessings.publicKey = '';
    tagPermsAuthorizer(ctx, call);
  }

  // Everyone is allowed via the Foo tag.
  testSuccessCase(assert, diffPublicKeyPermsAuthorizer, [tagFoo], true);
});

test('Test permissionsAuthorizer (tag) - failure', function(assert) {
  var tagBar = new access.Tag('Bar');

  function diffPublicKeyPermsAuthorizer(ctx, call) {
    // get rid of public key, just for this example to demonstrate failure
    call.remoteBlessings.publicKey = '';
    tagPermsAuthorizer(ctx, call);
  }

  // Nobody is allowed via the Bar tag.
  testErrorCase(assert, diffPublicKeyPermsAuthorizer, [tagBar], true);
});

test('Test allowEveryoneAuthorizer() - success', function(assert) {
  testSuccessCase(assert, allowEveryoneAuthorizer(), [], true);
});
