var rewire = require('rewire');

var CredentialsProvider = require('../../lib/credentials/CredentialsProvider.js').CredentialsProvider;
//required libs
var Response = require('../../lib/net/Response.js').Response;
var Loader = require('../../lib/net/Loader.js').Loader;
var OpalLoader = require('../../lib/opal/OpalLoader.js').OpalLoader;
var OpalResponse = require('../../lib/opal/OpalResponse.js').OpalResponse;
var JsonRpcResponse = require('../../lib/jsonrpc/JsonRpcResponse.js').JsonRpcResponse;
var Event = require('../../lib/event/Event.js').Event;

describe("OpalCredentialsProvider", function () {
    var MockOpalLoader;
    var OpalCredentialsProvider;
    var OpalCredentialsProviderMock;

    //Example client
    var ExampleCredentialClient = function (credentialsProvider) {
        this.credentialsProvider = credentialsProvider;
        //this.credentialsProvider.addEventListener(CredentialsProvider.Event.LOAD, this._onCredentialsLoad, this);

        this._credentials = null;
    }
    ExampleCredentialClient.prototype._onCredentialsLoad = function (e) {
        this._credentials = e.data;
        //creating pool itd
    };
    ExampleCredentialClient.prototype.get = function (key, callback) {
        //getting from pool itd
        this.credentialsProvider.get(function (err, credentials) {
            if (credentials) {
                callback(credentials);
            } else {
                expect(false).toBeTruthy();
            }
        });
    };
    var load = function () {};

    var exampleCredentialBase = {
        "prop1": "credential",
        "hosts": [{
            "host": "10.177.10.20",
            "port": "8080"
        },{
            "host": "10.177.60.60",
            "port": "1234"
        },{
            "host": "10.177.10.20",
            "port": "80"
        }],
        "abc": "123"
    };

    var exampleCredentialBaseSorted = {
        "abc": "123",
        "hosts": [{
            "host": "10.177.10.20",
            "port": "80"
        },{
            "host": "10.177.10.20",
            "port": "8080"
        },{
            "host": "10.177.60.60",
            "port": "1234"
        }],
        "prop1": "credential",
    };

    var exampleCredentialChanged = {
        "bcd": "credential22",
        "hosts": [{
            "host": "10.177.30.30",
            "port": "8080"
        },{
            "host": "10.177.30.20",
            "port": "1234"
        },{
            "host": "10.177.30.10",
            "port": "80"
        }],
        "abc": "123"
    };

    var exampleCredentialChangedSorted = {
        "abc": "123",
        "bcd": "credential22",
        "hosts": [{
            "host": "10.177.30.10",
            "port": "80"
        },{
            "host": "10.177.30.20",
            "port": "1234"
        },{
            "host": "10.177.30.30",
            "port": "8080"
        }]
    };

    beforeEach(function () {
        OpalCredentialsProviderMock = rewire('../../lib/opal/OpalCredentialsProvider.js');
        OpalCredentialsProvider = OpalCredentialsProviderMock.OpalCredentialsProvider;

        OpalLoaderMock = OpalCredentialsProviderMock.__get__('OpalLoader');
        spyOn(OpalLoaderMock.prototype, 'load').andCallFake(function () {
            load(this);
        });

        //require actualy tested class
        OpalCredentialsProvider.DEFAULT_REFRESH_TIME = 100;
        expect(OpalCredentialsProvider).not.toBeNull();
    });

	it("credentials supplier problems / retrieving error but with stale credetnials / provider usage", function () {
        var done = false;

        load = function (that) {
            setTimeout(function () {
                var response = new OpalResponse({
                    "statusCode": 200,
                    "headers": {},
                    "httpVersion": "1.0",
                    "body": new JsonRpcResponse("test", exampleCredentialBase)
                });
                that.dispatchEvent(new Event(OpalLoader.Event.JSON_RESPONSE, response));
            }, 1);
        };

        var provider = new OpalCredentialsProvider(
            "include-cache.membase.edgeserver.onetapi.pl",
            "edgeserver.edgeserver.onetapi.pl"
        );

		provider.get(function (err, credentials) {
			expect(err).toBeFalsy();
			expect(JSON.stringify(credentials)).toEqual(JSON.stringify(exampleCredentialBaseSorted));
			done = true;
		});

        waitsFor(function () {
            return done == true;
        });

        runs(function () {
			done = false;
			load = function (that) {
				setTimeout(function () {
					var response = new Response({
						"statusCode": 503,
						"headers": {},
						"httpVersion": "1.0",
						"body": ""
					});
					that.dispatchEvent(new Event(Loader.Event.ERROR, response));
				}, 1);
			};
			provider.refresh();
			provider.get(function (err, credentials) {
				expect(err).toBeTruthy();
				expect(JSON.stringify(credentials)).toEqual(JSON.stringify(exampleCredentialBaseSorted));
				done = true;
			});
        });

        waitsFor(function () {
            return done == true;
        });

        runs(function () {
			provider.destroy();
        });
    });

    it("standard provider-client usage", function () {
        var done = false;

        load = function (that) {
            setTimeout(function () {
                var response = new OpalResponse({
                    "statusCode": 200,
                    "headers": {},
                    "httpVersion": "1.0",
                    "body": new JsonRpcResponse("test", exampleCredentialBase)
                });
                that.dispatchEvent(new Event(OpalLoader.Event.JSON_RESPONSE, response));
            }, 1);
        };
        var provider = new OpalCredentialsProvider(
            "include-cache.membase.edgeserver.onetapi.pl",
            "edgeserver.edgeserver.onetapi.pl"
        );
        var exampleClient = new ExampleCredentialClient(provider);

        exampleClient.get("test", function (credentials) {
            expect(JSON.stringify(credentials)).toEqual(JSON.stringify(exampleCredentialBaseSorted));
            done = true;
        });

        waitsFor(function () {
            return done == true;
        });

        runs(function () {
            provider.destroy();
        });
    });

    it("provider-client usage - changed credentials", function () {
        var done = false;

        var response1 = new OpalResponse({
            "statusCode": 200,
            "headers": {},
            "httpVersion": "1.0",
            "body": new JsonRpcResponse("test", exampleCredentialBase)
        });

        var response2 = new OpalResponse({
            "statusCode": 200,
            "headers": {},
            "httpVersion": "1.0",
            "body": new JsonRpcResponse("test", exampleCredentialChanged)
        });

        load = function (that) {

            setTimeout(function () {
                that.dispatchEvent(new Event(OpalLoader.Event.JSON_RESPONSE, response1));
            }, 1);
        };
        //MockOpalLoader.prototype.load = function () {};
        var provider = new OpalCredentialsProvider(
            "example2",
            "example2"
        );
        provider.refreshTime = 100;
        var exampleClient = new ExampleCredentialClient(provider);

        runs(function () {
            done = false;

            exampleClient.get("test", function (credentials) {
                expect(JSON.stringify(credentials)).toEqual(JSON.stringify(exampleCredentialBaseSorted));
                done = true;
            });
        });

        waitsFor(function () {
            return done == true;
        });

        runs(function () {
            done = false;

            exampleClient.get("test", function (credentials) {
                expect(JSON.stringify(credentials)).toEqual(JSON.stringify(exampleCredentialBaseSorted));
                done = true;
            });
        });

        waitsFor(function () {
            return done == true;
        });

        runs(function () {
            done = false;

            load = function (that) {
                setTimeout(function () {
                    that.dispatchEvent(new Event(OpalLoader.Event.JSON_RESPONSE, response2));
                }, 1);
            };
        });

        waits(200);

        runs(function () {
            exampleClient.get("test", function (credentials) {
                expect(JSON.stringify(credentials)).toEqual(JSON.stringify(exampleCredentialChangedSorted));
                done = true;
            });
        });

        waitsFor(function () {
            return done == true;
        });

        runs(function () {
            provider.destroy();
        });
    });

});
