var assert = require ('assert');
var watchmen = require ('../lib/watchmen.js');
var redis_storage_class = require('../lib/storage/providers/redis');
var mocked_ping_service = require ('./lib/mock/request_mocked');
var sinon = require('sinon');
var service_loader = require ('../lib/services');

describe('redis storage', function(){

  //use redis_storage with testing environment
  var redis_storage = new redis_storage_class({port: 6666, host: '127.0.0.1', db: 0});
  var _watchmen = new watchmen(null, redis_storage);

  var services, service;

  var clock;

  var ok_response = {body : 'Apple Inc.', response : 200, timeDiff : 100};
  var warning_response = {body : 'Apple Inc.', response : 200, timeDiff : 5000};
  var error_response = {error: 'error', body : null, response : 500, timeDiff : 0};

  function pingAndGetReport(service, mocked_response, callback) {
    mocked_ping_service.mocked_response = mocked_response;
    _watchmen.ping({service:service}, function(err, request_status){
      redis_storage.report_one(service, function(err, service){
        assert.ifError(err);
        callback(err, service);
      });
    });
  }

  beforeEach(function(done){
    clock = sinon.useFakeTimers(+new Date());
    redis_storage.flush_database(done);
    service_loader.load_services(function(err, _services){
      services = _services;
      service = services[0];
      service.ping_service = mocked_ping_service; //assign mocked service
    });
  });

  after(function(done){
    clock.restore();
    done();
  });

  describe('status', function(){
    it('should update status', function(done){
      _watchmen.ping({service:service}, function(err, request_status){
        redis_storage.get_status(service, function(err, status){
          assert.equal (JSON.stringify(status), JSON.stringify(request_status));
          done();
        });
      });
    });
  });

  describe('reporting list', function(){
    it('should load info for all services', function(done){
      service_loader.load_services(function(err, _services){
        redis_storage.report_all(services, function(err, data){
          assert.ifError(err);
          assert.equal (data.services.length, 27); // not the best, should change when services get store in the DB
          done();
        });
      });
    });
  });

  describe('reporting details', function(){

    it('should return correct data on error response', function(done){
      pingAndGetReport(service, error_response, function(err, service){
        assert.equal (service.data.status, 'error');
        assert.equal (service.data.events.length, 1);
        assert.equal (service.data.events[0].status, 'error');
        assert.ok (service.data.events[0].timestamp);
        done();
      });
    });

    it('should return correct data on warning response', function(done){
      pingAndGetReport(service, warning_response, function(err, service){
        assert.equal (service.data.status, 'success');
        assert.equal (service.data.events.length, 1);
        assert.equal (service.data.events[0].status, 'warning');
        assert.ok (service.data.events[0].timestamp);
        done();
      });
    });

    it('should return correct data on successful response', function(done){
      pingAndGetReport(service, ok_response, function(err, service){
        assert.equal (service.data.status, 'success');
        assert.equal (service.data.events.length, 0);
        done();
      });
    });

    it('should return newest events first', function(done){
      pingAndGetReport(service, error_response, function(err, service){          
        pingAndGetReport(service, ok_response, function(err, service){
          assert.equal (service.data.status, 'success');
          assert.equal (service.data.events.length, 2);
          assert.equal (service.data.events[0].status, 'success'); // newest events to first
          done();
        });
      });
    });

    it('should purge old events with default expiration date', function(done){
      pingAndGetReport(service, error_response, function(err, service){          
        clock.tick(1000 * 60 * 60 * 24 * 10); // time travel 10 days
        pingAndGetReport(service, ok_response, function(err, service){
          assert.equal (service.data.status, 'success');
          assert.equal (service.data.events.length, 1);
          assert.equal (service.data.events[0].status, 'success'); // newest events to first
          done();
        });
      });
    });

    it('should purge old events with custom (per host) expiration date', function(done){
      service.host.remove_events_older_than_seconds = 1;
      pingAndGetReport(service, error_response, function(err, service){          
        clock.tick(1000); // time travel 1 second
        pingAndGetReport(service, ok_response, function(err, service){
          assert.equal (service.data.status, 'success');
          assert.equal (service.data.events.length, 1);
          assert.equal (service.data.events[0].status, 'success'); // newest events to first
          done();
        });
      });
    });

  });
});
