'use strict';

var chai = require('chai');
var should = chai.should();
var sinon = require('sinon');
var async = require('async');
var proxyquire = require('proxyquire');
var memdown = require('memdown');

var bitcoindjs = require('../');
var DB = bitcoindjs.DB;
var Chain = bitcoindjs.Chain;
var Block = bitcoindjs.Block;

var chainData = require('./data/testnet-blocks.json');

describe('Bitcoin Chain', function() {

  describe('@constructor', function() {
    
    it('can create a new instance with and without `new`', function() {
      var chain = new Chain();
      chain = Chain();
    });

  });

  describe('#start', function() {
    it('should call the callback when base chain is initialized', function(done) {
      var chain = new Chain();
      chain.bitcoind = {};
      chain.bitcoind.genesisBuffer = new Buffer('0100000043497fd7f826957108f4a30fd9cec3aeba79972084e90ead01ea330900000000bac8b0fa927c0ac8234287e33c5f74d38d354820e24756ad709d7038fc5f31f020e7494dffff001d03e4b6720101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0e0420e7494d017f062f503253482fffffffff0100f2052a010000002321021aeaf2f8638a129a3156fbe7e5ef635226b0bafd495ff03afe2c843d7e3a4b51ac00000000', 'hex');
      chain.initialize = function() {
        chain.emit('initialized');
      };

      chain.start(done);
    });
  });

  describe('#stop', function() {
    it('should call the callback', function(done) {
      var chain = new Chain();
      chain.stop(done);
    });
  });

  describe('#_writeBlock', function() {
    it('should update hashes and call putBlock', function(done) {
      var chain = new Chain();
      chain.db = {
        putBlock: sinon.stub().callsArg(1)
      };
      chain._writeBlock({hash: 'hash', prevHash: 'prevhash'}, function(err) {
        should.not.exist(err);
        chain.db.putBlock.callCount.should.equal(1);
        chain.cache.hashes.hash.should.equal('prevhash');
        done();
      });
    });
  });

  describe('#_validateBlock', function() {
    it('should call the callback', function(done) {
      var chain = new Chain();
      chain._validateBlock('block', function(err) {
        should.not.exist(err);
        done();
      });
    });
  });

  describe('#buildGenesisBlock', function() {
    it('can handle no options', function() {
      var db = {
        buildGenesisData: sinon.stub().returns({})
      };
      var chain = new Chain({db: db});
      var block = chain.buildGenesisBlock();
      should.exist(block);
      block.should.be.instanceof(Block);
      db.buildGenesisData.calledOnce.should.equal(true);
    });

    it('set timestamp, nonce, bits, merkleRoot and data of the genesis', function() {
      var db = {
        buildGenesisData: sinon.stub().returns({
          merkleRoot: 'merkleRoot',
          buffer: new Buffer('abcdef', 'hex')
        })
      };
      var chain = new Chain({db: db});
      var timestamp = '2015-03-20T14:46:01.118Z';
      var block = chain.buildGenesisBlock({
        timestamp: timestamp,
        nonce: 1,
        bits: 520617984
      });
      should.exist(block);
      block.should.be.instanceof(Block);
      block.timestamp.toISOString().should.equal(timestamp);
      block.nonce.should.equal(1);
      block.bits.should.equal(520617984);
      block.merkleRoot.should.equal('merkleRoot');
      block.data.should.deep.equal(new Buffer('abcdef', 'hex'));
      db.buildGenesisData.calledOnce.should.equal(true);
    });

  });

  describe('#getWeight', function() {
    var work = '000000000000000000000000000000000000000000005a7b3c42ea8b844374e9';
    var chain = new Chain();
    chain.db = {
      bitcoind: {
        getBlockIndex: sinon.stub().returns({
          chainWork: work
        })
      }
    };

    it('should give the weight as a BN', function(done) {
      chain.getWeight('hash', function(err, weight) {
        should.not.exist(err);
        weight.toString(16, 64).should.equal(work);
        done();
      });
    });

    it('should give an error if the weight is undefined', function(done) {
      chain.db.bitcoind.getBlockIndex = sinon.stub().returns(undefined);
      chain.getWeight('hash2', function(err, weight) {
        should.exist(err);
        done();
      });
    });
  });
});

@@ -752,32 +752,60 @@
 ();%0A      chain.
+node = %7B%7D;%0A      chain.node.
 bitcoind = %7B%7D;%0A 
@@ -815,16 +815,21 @@
   chain.
+node.
 bitcoind

Fix chain unit test.