let assert = require('assert');
import Redis from '../redis';
import Utils from '../utils';
import mockObjects from "../mockObjects";
import RedisMock from "../mocks/redisMock";
import * as Bluebird from "bluebird"

import * as IORedis from "ioredis";
import MockObjects from '../mockObjects';

let config = {
    statusCheckInterval: 1,
    keys: {
        rediskey_connections: "test:"
    }
};

describe('test redis', function () {

    it('lock_sesion with lua', function(done){
        let redis = MockObjects.makeRedis(config);

        let session = "1234";
        let free_session_list = "free_set"
        let used_session_key = "used_key";
        let lock_time = 200;

        redis.add_session(session,free_session_list, function(success, result){

            assert.equal(success, true);
            redis.lock_session_lua(free_session_list, used_session_key, lock_time, function(success, result){
                assert.equal(success, true);
                assert.equal(result, "1234"); //from redisMock.ts
                done();
            });
        });
    });

    it('lock_sesion with watch', function(done){
        let redis = MockObjects.makeRedis(config);

        let session = "1234";
        let free_session_list = "free_set"
        let used_session_key = "used_key";
        let lock_time = 200;

        redis.add_session(session,free_session_list, function(success, result){

            assert.equal(success, true);
            redis.lock_session_with_watch(free_session_list, used_session_key, lock_time, function(success, result){
                assert.equal(success, true);
                assert.equal(result, "1234"); //from redisMock.ts
                done();
            });
        });
    });

    it('lock_sesion', function(done){
        let redis = MockObjects.makeRedis(config);

        let session = "1234";
        let free_session_list = "free_set"
        let used_session_key = "used_key";
        let lock_time = 200;

        redis.add_session(session,free_session_list, function(success, result){

            assert.equal(success, true);
            redis.lock_session(free_session_list, used_session_key, lock_time, function(success, result){
                assert.equal(success, true);
                assert.equal(result, "1234"); //from redisMock.ts
                done();
            });
        });
    })

    it('create destroy', function (done) {
        class SpecialCase extends RedisMock{
            public quit(callback?: (err: Error, res: string) => void): Bluebird<string> {
                done();
                return super.quit();
            }
        }

        let redis = MockObjects.makeRedis(config, SpecialCase);
        redis.destroy();
    });
    
    it('test functions: set, get, delete', function (done) {
        let redis = MockObjects.makeRedis(config);

        redis.close();
        redis.set("unit_test", "unit_test_re");
        redis.get("unit_test", function(isSucces: boolean, result: any){
            assert.equal(isSucces, true);
            assert.equal(result, "unit_test_re");
        });
        redis.delete("unit_test");
        redis.get("unit_test", function(isSucces: boolean, result: Error){
            assert.equal(isSucces, false);
            assert.notEqual(result, null);           
            assert.equal(result.message, "Undefined value");
            done();
        });
    });

    it('status change', function (done) {
        let getStatus = function(){
            return "default";
        }
        let destroy = function(){}
        class SpecialCase extends RedisMock{
            private i = 0;
            public quit(callback?: (err: Error, res: string) => void): Bluebird<string> {
                done();
                return super.quit();
            }

            public set(key: string, value: any, ...args: any[]){
                let callback = args[0];
                let status = getStatus();

                this.i += 1;
                if(status == "default") this.i = 1;//Start to increment just after chenge getStatus function
                switch(this.i){
                    case 1:
                        //We cant know if is first or secand call
                        if(typeof callback === "function") callback(null, null);
                        break;
                    case 2:
                        assert.equal(getStatus(), "connected")
                        if(typeof callback === "function") callback(new Error(), null);
                        break;
                    case 3:
                        assert.equal(getStatus(), "disconnected")                
                        destroy();                    
                        break;
                }
            }
        }

        let redis = MockObjects.makeRedis(config, SpecialCase);        
        getStatus = function() { return redis.getStatus(); };
        destroy = function() { redis.destroy(); };
    });

    it('test hset, hget', function (done) {
        class SpecialCase extends RedisMock{
            private memory: {[key: string]: string} = {};

            public hset(key: string, field: string, value: any, callback?: (err: Error, res: 0 | 1) => void): Bluebird<0 | 1> { 
                assert.equal(key, "key");
                this.memory[field] = value;
                if(callback != undefined) callback(<any>null, 1);

                return super.hset(key, field, value);
            }

            public hget(key: string, field: string, callback?: (err: Error, res: string) => void): Bluebird<string> {
                assert.equal(key, "key");
                let val = this.memory[field];
                if(val != null){
                    if(callback != undefined) callback(<any>null, val);
                }else{
                    if(callback != undefined) callback(new Error("error"), <any>null);
                }
                 return super.hget(key, field);
            }

            public hgetall(key: string, callback?: (err: Error, res: any) => void): Bluebird<any> { 
                assert.equal(key, "key");
                if(callback != undefined) callback(<any>null, this.memory);

                return super.hgetall(key);
             };

             public hdel(key: string, field?: string, ...fields: any[]): any {

                let neededField = "";
                if(field == undefined){
                    done("expected field");
                }else{
                    neededField = field;
                }
                let callback = fields[0];

                assert.equal(key, "key");
                let val = this.memory[neededField];
                if(val != null){
                    delete this.memory[neededField];
                    if(callback != undefined) callback(null, 1);
                }else{
                    if(callback != undefined) callback(new Error("error"), null);
                }
             };
        }
        let redis = MockObjects.makeRedis(config, SpecialCase);
        
        redis.hset("key", "label", "value", function(isSucces: boolean, response: any){
            assert.equal(isSucces, true);
            assert.equal(response, 1);

            redis.hset("key", "label2", "value2", function(isSucces: boolean, response: any){
                assert.equal(isSucces, true);
                assert.equal(response, 1);

                redis.hget("key", "label", function(isSucces: boolean, response: any){
                    assert.equal(isSucces, true);
                    assert.equal(response, "value");
                    redis.hgetall("key", function(isSucces: boolean, response: any){
                        assert.equal(isSucces, true);
                        assert.equal(JSON.stringify(response), JSON.stringify({label: "value", label2: "value2"}));
                        redis.hdel("key", "label", function(isSucces: boolean, response: any){
                            assert.equal(isSucces, true);
                            assert.equal(response, 1);
                            redis.hget("key", "label", function(isSucces: boolean, response: any){
                                assert.equal(isSucces, false);
                                if(response instanceof Error){
                                    assert.equal(response.message, "error");
                                }else{
                                    done("expected Error")
                                }
                                done();
                            })
                        })
                    })
                })
            })
        })
    });

    it('test hset, hget (error case)', function (done) {
        class SpecialCase extends RedisMock{
            private memory: {[key: string]: string} = {};

            public hset(key: string, field: string, value: any, callback?: (err: Error, res: 0 | 1) => void): Bluebird<0 | 1> { 
                assert.equal(key, "key");
                assert.equal(field, "label");
                assert.equal(value, "value");
                this.memory[field] = value;
                if(callback != undefined) callback(new Error("error"), <any>null);

                return super.hset(key, field, value);
            }

            public hget(key: string, field: string, callback?: (err: Error, res: string) => void): Bluebird<string> {
                assert.equal(key, "key");
                assert.equal(field, "label");
                if(callback != undefined) callback(new Error("error"), <any>null);
                return super.hget(key, field);
            }

            public hgetall(key: string, callback?: (err: Error, res: any) => void): Bluebird<any> { 
                assert.equal(key, "key");
                if(callback != undefined) callback(new Error("error"), null);

                return super.hgetall(key);
             };

             public hdel(key: string, field?: string, ...fields: any[]): any {

                let callback = fields[0];
                assert.equal(key, "key");
                assert.equal(field, "label");
                if(callback != undefined) callback(new Error("error"), null);

             };
        }
        let redis = MockObjects.makeRedis(config, SpecialCase);
        
        redis.hset("key", "label", "value", function(isSucces: boolean, response: any){
            assert.equal(isSucces, false);
            if(response instanceof Error){
                assert.equal(response.message, "error");
            }else{
                done("expected Error")
            }
            
            redis.hget("key", "label", function(isSucces: boolean, response: any){
                assert.equal(isSucces, false);
                if(response instanceof Error){
                    assert.equal(response.message, "error");
                }else{
                    done("expected Error")
                }

                redis.hgetall("key", function(isSucces: boolean, response: any){
                    assert.equal(isSucces, false);
                    if(response instanceof Error){
                        assert.equal(response.message, "error");
                    }else{
                        done("expected Error")
                    }

                    redis.hdel("key", "label", function(isSucces: boolean, response: any){
                        assert.equal(isSucces, false);
                        if(response instanceof Error){
                            assert.equal(response.message, "error");
                        }else{
                            done("expected Error")
                        }
    
                        done();
                    });
                })
            })
        })
    });
});        