import Logger from "./logger";
import Redis from "./redis";
import Cassandra from "./cassandra";
import Elastic from "./elastic";
import Mysql from "./mysql";
import Mailer from "./mailer";
import Registry from "./metrics";
import MIM from "./multipleInstanceManager";
import Crashreporter from "./crashreporter";
import Consul from "./consul";

import * as Prom from "prom-client";
const promBundle = require("express-prom-bundle");

interface Status {
    redis: string | Object;
    cassandra: string | Object;
    elastic: string | Object;
    mailer: string | Object;
    mysql: string | Object;
    consul: string | Object;
}

export default class Global {
    protected static instance: Global;

    public personalStatus: () => any = function(){return null;}
    public personalIsFunctional: () => boolean = function(){return true;}

    private loggers: MIM<Logger> | null = null;
    private redises: MIM<Redis> | null = null;
    private cassandras: MIM<Cassandra> | null = null;
    private elastics: MIM<Elastic> | null = null;
    private mysqls: MIM<Mysql> | null = null;     
    private mailers: MIM<Mailer> | null = null;
    private metrics: MIM<Registry> | null = null;
    private crashreporters: MIM<Crashreporter> | null = null;
    private consuls: MIM<Consul> | null = null;
    

    public static get Instance() {
        if (this.instance === null || this.instance === undefined) {
            this.instance = new this();
        }
        return this.instance;
    }

    get Loggers(){
        if(this.loggers == null){
            this.loggers = new MIM(Logger);
        }
        return this.loggers;
    }

    get Redis(){
        if(this.redises == null){
            this.redises = new MIM(Redis);
        }
        return this.redises;
    }

    get Cassandras(){
        if(this.cassandras == null){
            this.cassandras = new MIM(Cassandra);
        }
        return this.cassandras;
    }

    get Elastics(){
        if(this.elastics == null){
            this.elastics = new MIM(Elastic);
        }
        return this.elastics;
    }

    get Mysql(){
        if(this.mysqls == null){
            this.mysqls = new MIM(Mysql);
        }
        return this.mysqls;
    }

    get Mailers(){
        if(this.mailers == null){
            this.mailers = new MIM(Mailer);
        }
        return this.mailers;
    }

    get Metrics(){
        if(this.metrics == null){
            this.metrics = new MIM(Registry);
        }
        return this.metrics;
    }

    get Crashreporters(){
        if(this.crashreporters == null){
            this.crashreporters = new MIM(Crashreporter);
        }
        return this.crashreporters;
    }
    
    get Consuls(){
        if(this.consuls == null){
            this.consuls = new MIM(Consul);
        }
        return this.consuls;
    }

    /**
     * 
     */
    public getMergedMetrics(): Prom.Registry{
        // TODO : register already reports all metrics, the merge is redundant or even dangerous
        if(this.metrics != null){
            let values = this.metrics.getValues();
            let registry: Prom.Registry[] = [];
            values.forEach(element => {
                registry.push(element.getRegistry());
            });
            return promBundle.promClient.Registry.merge(registry);
        }else{
            return promBundle.promClient.register;
        }
    }

    /**
     * pure visual method, return the stastus of the connections in more human readable fashion
     */
    public getStatus(){
        /**
         * default values
         */
        let response: Status = {
            redis: "inactive",
            cassandra: "inactive",
            elastic: "inactive",
            mailer: "inactive",
            mysql: "inactive",
            consul: "inactive"
        };

        /**
         * put the status of the connection if we are using that connection
         */
        this.redises != null ? response["redis"] = this.redises.getStatus() : "";
        this.cassandras != null ? response["cassandra"] = this.cassandras.getStatus() : "";
        this.elastics != null ? response["elastic"] = this.elastics.getStatus() : "";
        this.mailers != null ? response["mailer"] = this.mailers.getStatus() : "";
        this.mysqls != null ? response["mysql"] = this.mysqls.getStatus() : "";
        this.consuls != null ? response["consul"] = this.consuls.getStatus() : "";

        /**
         * add extra custom visual checks
         */
        let personal = this.personalStatus();
        if(personal != null){
            return {
                base: response,
                personal : personal
            }
        }

        //return the composed response
        return response;
    }

    /**
     * check the status of the main components
     * 
     * @return true|false
     */
    public isFunctional(){
        let redis = this.redises != null ? this.redises.isFunctional() : true;
        let cassandra = this.cassandras != null ? this.cassandras.isFunctional() : true;
        let elastic = this.elastics != null ? this.elastics.isFunctional() : true;
        let mysql = this.mysqls != null ? this.mysqls.isFunctional() : true;

        return redis && cassandra && elastic && mysql && this.personalIsFunctional();
    }
}