import Redis from "./redis";
import Cassandra from "./cassandra";
import Elastic from "./elastic";
import WebServer from "./express";
import MysqlModule from "./mysql";
import * as Index from "./index.d";
import * as Elasticsearch from 'elasticsearch';
import * as Mysql from 'mysql';
import Settings from "./settings";

import RedisLibMock from "./mocks/redisMock";
import ElasticLibMock from "./mocks/elasticMock";
import CassandraMock from "./mocks/cassandraMock";
import MysqlLibMock from "./mocks/mysqlMock";

export default class MockObjects {
    public static makeRedis(config: Index.RedisOptions = {}, redisLibrary?: new () => Index.ExtendedIORedis): Redis{
        let library = redisLibrary != undefined ? redisLibrary : RedisLibMock;

        class MockRedis extends Redis {        
            public connect() {
                this.redis = new library();
            }

            public begin_transaction(): any{
                if(this.redis != null)
                    return this.redis.multi();
            }

            exec_transaction(redis_transactions: any, callback: (isSucces: boolean, result: any) => void){ 
                callback(true, "1234");
            }
        }

        Settings.Instance.resetRedis("mock");
        Settings.Instance.setRedis("mock", config);
        return new MockRedis("mock");
    }

    public static makeMysql(config: Index.MysqlOptions = {}, mysqlLibrary?: new () => Mysql.Connection): MysqlModule{
        let library = mysqlLibrary != undefined ? mysqlLibrary : MysqlLibMock;

        class MockMysql extends MysqlModule {        
            public connect() {
                this.mysql = new library();
            }
        }

        Settings.Instance.resetMysql("mock");
        Settings.Instance.setMysql("mock", config);
        return new MockMysql("mock");
    }

    public static makeElastic(config: Index.ElasticOptions = {}, elasticLibrary?:  new (params: Elasticsearch.ConfigOptions) => Elasticsearch.Client): Elastic{
        let library = elasticLibrary != undefined ? elasticLibrary : ElasticLibMock;

        class MockElastic extends Elastic {
            public connect() {
                this.elastic = new library({});
            }
        }

        Settings.Instance.resetElastic("mock");
        Settings.Instance.setElastic("mock", config);
        return new MockElastic("mock");
    }

    public static makeCassandra(config: Index.CassandraOptions = {}, 
        cassandraLibrary?: new (options: Index.CassandraOptions, 
            errorCallback: (err: any) => void, 
            successCallback: () => void, 
            callbackStatus: (err: any) => void) => Index.ExtendedCassandraClient
        ): Cassandra{
            let library = cassandraLibrary != undefined ? cassandraLibrary : CassandraMock;

            class MockCassandra extends Cassandra {
                public connect(onSuccess: {(): void} | null = null, onError: {(err: any): void} | null = null) {
                    let self = this;
                        this.cassandra = new library(
                            {},
                            function (err) {
                                if (typeof onError == "function") {
                                    onError(err);
                                }
                            }
                            ,
                            function () {
                                if (typeof onSuccess == "function") {
                                    onSuccess();
                                }
                            },
                            function (err: any) {
                                self.setStatus(err);
                            }
                        );
                }
            }

            Settings.Instance.resetCassandra("mock");
            Settings.Instance.setCassandra("mock", config);
            return new MockCassandra("mock");
    }

    public static makeWebServer(config: Index.ModuleOptions){
        class MockWebServer extends WebServer {
            public handleWriteStream(write: any) {
                this.logStream.write = write;
            }
            public mockCustomGenerator(time: Date, index: number){
                return this.customGenerator(time, index);
            }
        }

        Settings.Instance.resetSwagger("mock");
        Settings.Instance.resetMorgan("mock");
        Settings.Instance.setSwagger("mock", config.swagger ? config.swagger : {});
        Settings.Instance.setMorgan("mock", config.morgan ? config.morgan : {});
        return new MockWebServer("mock");
    }
}