import * as Index from "./index.d";
import * as CassandraTypes from "cassandra-driver";
import CustomCassandraConnectionPool from "./customCassandraPool";
import { MultipleInstanceInterface } from "./multipleInstanceInterface";
import Settings from "./settings";

export default class Cassandra implements MultipleInstanceInterface{
    private config: Index.CassandraOptions;
    private tag: string;

    protected cassandra: Index.ExtendedCassandraClient | null = null;
    protected status: string;

    constructor(tag: string = "global") {
        this.status = "";
        this.config = Settings.Instance.getCassandra(tag);
        this.tag = tag;

        if(this.config.autoConnect){
            this.connect();            
        }
    }

    public destroy(): void{
        if(this.cassandra == null) return;

        this.cassandra.shutdown();
        this.cassandra = null;
    }

    public connect(onSuccess: {(): void} | null = null, onError: {(err: any): void} | null = null): void {
        let self = this;
        let cassandra = new CustomCassandraConnectionPool(
            this.config,
            function(err){
                if(typeof onError == "function"){
                    onError(err);
                }
            },
            function(){
                if(typeof onSuccess == "function"){
                    onSuccess();
                }
            },
            function(err){
                self.setStatus(err);
            }
        );
        this.cassandra = cassandra.client;
    }

    protected setStatus(err: any): void{
        if(err != null){
            // self.handleError(err);
            this.status = "Error";
        }else{
            // self.logger.log('Cassandra connect successful', base.LOG_LEVEL.INFO);
            if(this.status == ""){
                this.status = "Connected";
            }else{
                this.status = "Reconnected";
            }
        }
    }

    private tryToConnect(response?: (err: Error, result: CassandraTypes.types.ResultSet | null) => void): boolean{
        if(this.cassandra == null){
            if(this.config.autoConnect){
                this.connect();
                return true;
            }else{
                if(response)
                    response(new Error("Do not have a connection"), null);
                return false;
            }
        }
        return true;
    }

    public close(){
        if(this.cassandra == null) return;

        this.cassandra.shutdown();        
    }

    public execute(query: string, params?: any, options?: CassandraTypes.QueryOptions, callback?: (err: Error, result: CassandraTypes.types.ResultSet | null) => void){
        if(!this.tryToConnect(callback)) return;

        if(this.cassandra != null){
            this.cassandra.execute(query, params, options, callback);           
        }
    }

    public getControlConnection(): any | null{
        if(this.cassandra == null) return null;
        return this.cassandra.controlConnection;
    }

    /**
     * return the status of the inner redis connection
     */
    public getStatus(): string{
        return this.status;
    }

    public isFunctional(): boolean{
        return this.getStatus() == "Connected" || this.getStatus() == "Reconnected";
    }

    public getCurrentKeyspace(): string | undefined{
        return this.config.keyspace;
    }
}