/**
 * For more detailde exemple check templates
 */
// process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
import * as Express from "express";
import * as http from "http";
import * as Index from "../index.d";
import * as MysqlType from "mysql";
import { resolve } from "bluebird";

class FullWebServer {
    public base = require('../index');// replace with let base = require('node-base-module');
    public app: Express.Express;
    public server: http.Server;

    constructor() {
        let self: FullWebServer = this;
        /**
         * Default initialization can be found in node-base-module/options.json
         * To set your custom setting can use base.setDefaultOptions or base.resetDefaultOptions
         * Both functions will replace global the default settings
         * If some settings is missing from new setting module will keep the old one
         * Express use from setting just next groups:
         *      "swagger" - to configurate the swagger if swagger/isActive are true else swagger will not be integrated
         *      "morgan" - to specify if morgan is integrated or not
         *      "logStream" - to configurate the acces log
         */

        this.base.setDefaultFileOptions("../../src/demo/fullWebServerConfig.json");
        process.env["OVERWRITTEN_SETTING"] = "was overwritted";
        this.base.setEnvMap({
            OVERWRITTEN_SETTING: {
                route: ["custom", "env_overwritten"],
                type: "string"                
            }
        });
        this.base.setCustomSettings({
            value: "from custom settings",
            env_overwritten: "this should be overwritten" 
        });


        /**
         * Module will create crashreporter with configuration established
         * in default config "./options.json (crashreporter)" or specified by you using base.setDefaultOptions()
         * in any point before this
         */
        this.base.crashreporter();


        /**
         * Get your own express web server
         * You can use base.express()
         * Here you can alse specifay custom setting without affecting global setting
         * Any setting specifay to this function will afect just that express instance
         */
        var express = this.base.express();


        /**
         * Generate an express client
         * To get access to express client use express.initialize()
         * At this point if you skip "Step 3." will be generated a default "log stream"
         * else will be youse your own "log stream"
         * Same for setting, if you set options.morgan.isActive to false, will not be integrate morgane
         * to your express client. Same for this.options.swagger.isActive.
         */
        this.app = express.initialize();
        this.base.metrics.newInstance("test");
        this.base.metrics("test").newGauge("test_val", "valuare_test", [], (this.base.AGGREGATORS.MIN | this.base.AGGREGATORS.AVERAGE | this.base.AGGREGATORS.MAX));
        
        /**
         * Include routes (with swagger documentation)
         * To include your own route use express client generated at "Step 5" with function express.initialize()
         */

        /**
         * @swagger
         * /:
         *   get:
         *     summary: Get
         *     description:
         *       "info page"
         *     tags:
         *       - Comands
         *     produces:
         *         - "application/json"
         *     responses:
         *       200:
         *         description: OK
         */
        this.app.get('/', function (req, res, next) {
            res.setHeader('Content-Type', 'application/json');
            res.status(200);
            res.send(JSON.stringify({
                "info": "To be fully functional run docker-compose.yml",
                "available_routes":[
                    "/",
                    "/test",
                    "/elastic_set",
                    "/elastic_get",
                    "/elastic_delete",
                    "/redis_set",
                    "/redis_get",
                    "/redis_delete",
                    "/cassandra_create",
                    "/cassandra_set",
                    "/cassandra_get",
                    "/cassandra_delete",
                    "/mysql_set",
                    "/mysql_get",
                    "/send_mail",
                    "/crash_server"
                ],
                "routes_included_by_modul":[
                    "/health",
                    "/swagger.json",
                    "/metrics"
                ],
                "utils_ports":{
                    "8081": "interface for redis",
                    "80": "interface for swagger(link with /swagger.json)",

                },
                "exercise": [
                    "check command /health",
                    "will see elastic: 'inactive'",
                    "because nowhere in project is used leastic",
                    "use command /elastic_set",
                    "this command use an elastic connection",
                    "so it wiil automate create an connection",
                    "based on you configuration",
                    "check command /health again",
                    "will see status of global connection",
                    "this connection is keeped until you delete it"
                ],
                "Attention": [
                    "To be able to use /send_mail and /crash_server",
                    "you need to configurate it with real data.",
                    "Check 'this.base.setDefaultOptions()' from",
                    "beginning of src/demo/fullWebServer.ts"
                ]
            }));
        });

        /**
         * @swagger
         * /test:
         *   get:
         *     summary: Get
         *     description:
         *       "Make test request"
         *     tags:
         *       - Comands
         *     produces:
         *         - "application/json"
         *     responses:
         *       200:
         *         description: OK
         */
        this.app.get('/test', function (req, res, next) {
            self.base.metrics("test").gauge("test_val").reset();            
            self.base.metrics("test").gauge("test_val").set(Math.random());
            res.setHeader('Content-Type', 'application/json');
            res.status(200);
            res.send(JSON.stringify({result: "Our test response", settings: self.base.getSettings()}));
        });


        /**
         * @swagger
         * /elastic_set:
         *   get:
         *     summary: Get
         *     description:
         *       "save object to elastic"
         *     tags:
         *       - Comands
         *     produces:
         *         - "application/json"
         *     responses:
         *       200:
         *         description: OK
         */
        this.app.get('/elastic_set', function (req, res, next) {
            res.setHeader('Content-Type', 'application/json');
            self.base.elastic().index(
                {
                    index: 'myindex',
                    type: 'mytype',
                    id: '1',
                    body: {
                        title: 'Test 1',
                        tags: ['y', 'z'],
                        published: true,
                    }
                }, function (error: any, response: any) {
                    res.status(200);
                    if (error != null) {
                        res.send(JSON.stringify({error: error}));
                    } else {
                        res.send(JSON.stringify({result: response}));
                    }
                });
        });


        /**
         * @swagger
         * /elastic_get:
         *   get:
         *     summary: Get
         *     description:
         *       "get object from elastic"
         *     tags:
         *       - Comands
         *     produces:
         *         - "application/json"
         *     responses:
         *       200:
         *         description: OK
         */
        this.app.get('/elastic_get', function (req, res, next) {
            res.setHeader('Content-Type', 'application/json');
            res.status(200);
            self.base.elastic().get(
                {
                    index: 'myindex',
                    type: 'mytype',
                    id: '1'
                }, function (error: any, response: any) {
                    if (error != null) {
                        res.send(JSON.stringify({error: error}));
                    } else {
                        res.send(JSON.stringify({result: response}));
                    }
                });
        });


        /**
         * @swagger
         * /elastic_delete:
         *   get:
         *     summary: Get
         *     description:
         *       "delete object from elastic"
         *     tags:
         *       - Comands
         *     produces:
         *         - "application/json"
         *     responses:
         *       200:
         *         description: OK
         */
        this.app.get('/elastic_delete', function (req, res, next) {
            res.setHeader('Content-Type', 'application/json');
            res.status(200);
            self.base.elastic().delete(
                {
                    index: 'myindex',
                    type: 'mytype',
                    id: '1'
                }, function (error: any, response: any) {
                    if (error != null) {
                        res.send(JSON.stringify({error: error}));
                    } else {
                        res.send(JSON.stringify({result: response}));
                    }
                });
        });


        /**
         * @swagger
         * /redis_set:
         *   get:
         *     summary: Get
         *     description:
         *       "Save value to redis"
         *     tags:
         *       - Comands
         *     produces:
         *         - "application/json"
         *     responses:
         *       200:
         *         description: OK
         */
        this.app.get('/redis_set', async function (req, res, next) {
            res.setHeader('Content-Type', 'application/json');
    
            self.base.redis().set("redis_exemple", "redis test value", function (isSucces: boolean, result: any) {
                res.status(200);
                return res.send(JSON.stringify({result: result}));
            });
        });

        /**
         * @swagger
         * /cassandra_create:
         *   get:
         *     summary: Get
         *     description:
         *       "Create keyspace and table in cassandra"
         *     tags:
         *       - Comands
         *     produces:
         *         - "application/json"
         *     responses:
         *       200:
         *         description: OK
         *       500:
         *         description: ERROR
         */
        this.app.get('/cassandra_create', function (req, res, next) {
            res.setHeader('Content-Type', 'application/json');
            let keyspaceCQL = "CREATE  KEYSPACE IF NOT EXISTS keyspace_name WITH REPLICATION = { "+
                                "'class' : 'NetworkTopologyStrategy', "+
                                "'datacenter1' : 1 "+
                            "}";
            let tableCQL = "CREATE TABLE IF NOT EXISTS test ( id UUID PRIMARY KEY, test_column text)";
            self.base.cassandra().execute(keyspaceCQL, [], {}, function(err: any, results: any){
                    if(err != null){
                        res.status(500);
                        return res.send(JSON.stringify({error: err}));
                    }

                    self.base.cassandra.configurate({
                        keyspace: "keyspace_name"
                    });
                    self.base.cassandra().execute(tableCQL, [], {}, function(err: any, results: any){
                        if(err != null){
                            res.status(500);
                            return res.send(JSON.stringify({error: err}));
                        }
                        res.status(200);
                        return res.send(JSON.stringify({result: results}));
                    });
                    
            });
        });

        /**
         * @swagger
         * /cassandra_set:
         *   get:
         *     summary: Get
         *     description:
         *       "Insert data in cassandra"
         *     tags:
         *       - Comands
         *     produces:
         *         - "application/json"
         *     responses:
         *       200:
         *         description: OK
         *       500:
         *         description: ERROR
         */
        this.app.get('/cassandra_set', function (req, res, next) {
            res.setHeader('Content-Type', 'application/json');   
            let insertQCL = "INSERT INTO test (id, test_column) VALUES (cfd66ccc-d857-4e90-b1e5-df98a3d40cd6, 'test_val') USING TTL 86400";
            self.base.cassandra().execute(insertQCL, [], {}, function(err: any, results: any){
                    if(err != null){
                        res.status(500);
                        return res.send(JSON.stringify({result: "First execute '/cassandra_create'", error: err}));
                    }
                        res.status(200);
                        return res.send(JSON.stringify({result: results}));
            });
        });

        /**
         * @swagger
         * /cassandra_get:
         *   get:
         *     summary: Get
         *     description:
         *       "Get data from cassandra"
         *     tags:
         *       - Comands
         *     produces:
         *         - "application/json"
         *     responses:
         *       200:
         *         description: OK
         *       500:
         *         description: ERROR
         */
        this.app.get('/cassandra_get', function (req, res, next) {
            res.setHeader('Content-Type', 'application/json');   
            let insertQCL = "SELECT * from test";
            self.base.cassandra().execute(insertQCL, [], {}, function(err: any, results: any){
                    if(err != null){
                        res.status(500);
                        return res.send(JSON.stringify({result: "First execute '/cassandra_create'", error: err}));
                    }
                        res.status(200);
                        return res.send(JSON.stringify({result: results}));
            });
        });


        /**
         * @swagger
         * /cassandra_delete:
         *   get:
         *     summary: Get
         *     description:
         *       "Delete data from cassandra"
         *     tags:
         *       - Comands
         *     produces:
         *         - "application/json"
         *     responses:
         *       200:
         *         description: OK
         *       500:
         *         description: ERROR
         */
        this.app.get('/cassandra_delete', function (req, res, next) {
            res.setHeader('Content-Type', 'application/json');   
            let insertQCL = "DELETE FROM test WHERE id=cfd66ccc-d857-4e90-b1e5-df98a3d40cd6 IF EXISTS";
            self.base.cassandra().execute(insertQCL, [], {}, function(err: any, results: any){
                    if(err != null){
                        res.status(500);
                        return res.send(JSON.stringify({result: "First execute '/cassandra_create'", error: err}));
                    }
                        res.status(200);
                        return res.send(JSON.stringify({result: results}));
            });
        });


        /**
         * @swagger
         * /redis_get:
         *   get:
         *     summary: Get
         *     description:
         *       "Get value from redis"
         *     tags:
         *       - Comands
         *     produces:
         *         - "application/json"
         *     responses:
         *       200:
         *         description: OK
         *       500:
         *         description: ERROR
         */
        this.app.get('/redis_get', function (req, res, next) {
            res.setHeader('Content-Type', 'application/json');
            self.base.redis().get("redis_exemple", function (isSucces: boolean, result: any) {
                if (!isSucces) {
                    res.status(503);
                    let strErr = "Dont find redis_exemple in redis db";
                    return res.send(JSON.stringify({ error: strErr }));
                }
                if (result) {
                    res.status(200);
                    return res.send(JSON.stringify({result: result}));
                }
            });
        });


        /**
         * @swagger
         * /redis_delete:
         *   get:
         *     summary: Get
         *     description:
         *       "Delete value vrom redis"
         *     tags:
         *       - Comands
         *     produces:
         *         - "application/json"
         *     responses:
         *       200:
         *         description: OK
         */
        this.app.get('/redis_delete', function (req, res, next) {
            res.setHeader('Content-Type', 'application/json');
            self.base.redis().delete("redis_exemple", function (isSucces: boolean, result: any) {
                res.status(200);
                return res.send(JSON.stringify({result: result}));
            });
        });

        /**
         * @swagger
         * /send_mail:
         *   get:
         *     summary: Get
         *     description:
         *       "Send a mail"
         *     tags:
         *       - Comands
         *     produces:
         *         - "application/json"
         *     responses:
         *       200:
         *         description: OK
         *       500:
         *         description: ERROR
         */
        this.app.get('/send_mail', function (req, res, next) {
            res.setHeader('Content-Type', 'application/json');
            self.base.mailer().sendMail({text: "test message from node-base-module/src/demo/fullWebServer.ts"}, function(error: any, response: any){
                if (error) {
                    res.status(503);
                    let strErr = "You need to configurate mailer with real data to be able to test this function";
                    return res.send(JSON.stringify({result: strErr, error: error.message }));
                }else{
                    res.status(200);
                    return res.send(JSON.stringify({result: response}));
                }
            });
        });


        /**
         * @swagger
         * /mysql_set:
         *   get:
         *     summary: Get
         *     description:
         *       "Insert data in mysql"
         *     tags:
         *       - Comands
         *     produces:
         *         - "application/json"
         *     responses:
         *       200:
         *         description: OK
         *       500:
         *         description: ERROR
         */
        this.app.get('/mysql_set', function (req, res, next) {
            res.setHeader('Content-Type', 'application/json');   
            let sql = "INSERT INTO test (name, value) VALUES (\"test name\", \"OK\")";
            self.base.mysql().query(sql, function(err: MysqlType.MysqlError | null, results?: any, fields?: MysqlType.FieldInfo[]){
                if(err != null){
                    res.status(500);
                    return res.send(JSON.stringify({result: "", error: err}));
                }
                    res.status(200);
                    return res.send(JSON.stringify({result: results}));
            });
        });

        /**
         * @swagger
         * /mysql_get:
         *   get:
         *     summary: Get
         *     description:
         *       "Get data from mysql"
         *     tags:
         *       - Comands
         *     produces:
         *         - "application/json"
         *     responses:
         *       200:
         *         description: OK
         *       500:
         *         description: ERROR
         */
        this.app.get('/mysql_get', function (req, res, next) {
            res.setHeader('Content-Type', 'application/json');   
            let sql = "Select * from test";
            self.base.mysql().query(sql, function(err: MysqlType.MysqlError | null, results?: any, fields?: MysqlType.FieldInfo[]){
                if(err != null){
                    res.status(500);
                    return res.send(JSON.stringify({result: "", error: err}));
                }
                    res.status(200);
                    return res.send(JSON.stringify({result: results}));
            });
        });

                /**
         * @swagger
         * /send_mail:
         *   get:
         *     summary: Get
         *     description:
         *       "Crash app to check crashreporter functionality"
         *     tags:
         *       - Comands
         *     produces:
         *         - "application/json"
         *     responses:
         *       200:
         *         description: OK
         *       500:
         *         description: ERROR
         */
        this.app.get('/crash_server', function (req, res, next) {
            process.emit("uncaughtException", new Error("Controlled Exception"));
        });

        /**
         * Also you can check auto generated routes:
         *      "/health" for functionality
         *      "/swagger.json" for swagger documentation
         */

        /**
         * Public your webserver
         */
        let port = 9876;
        this.server = this.app.listen(port);
    }
}


new FullWebServer();
