'use strict';

const Joi = require('joi');
const Knex = require('knex');
const Rfr = require('rfr');

const ComSrv = Rfr('/server/comsrv');

let db = null;

const connectToDB = async () => {
    ComSrv.debug(`Connecting to ${process.env.DB_HOST}:${process.env.DB_PORT} as ` +
        `${process.env.DB_USER} (type: ${process.env.DB_TYPE}, ` +
        `DB: ${process.env.DB_DATABASE})`);

    let db = Knex({
        client: process.env.DB_TYPE,
        connection: {
            host: process.env.DB_HOST,
            port: process.env.DB_PORT,
            user: process.env.DB_USER,
            password: process.env.DB_PASS,
            database: process.env.DB_DATABASE
        },
        log: {
            warn(message) { console.warn(message) },
            error(message) { console.error(message) },
            debug(message) { ComSrv.debug(message) }
        }
    });

    await db.raw('select 1 as connected');
    console.log('Connected to DB');

    return db;
}

module.exports = {
    config: Joi.object({
        DB_TYPE: Joi.string().valid('pg', 'mysql'),
        DB_HOST: Joi.alternatives().try(Joi.string().hostname(), Joi.string().ip()),
        DB_USER: Joi.string().min(1),
        DB_PASS: Joi.string().min(1),
        DB_DATABASE: Joi.string().min(1),
        DB_TABLE: Joi.string().min(1),

        DB_PORT: Joi.number().port().optional().when('DB_TYPE', {
            is: Joi.string().valid('pg'),
            then: Joi.number().default(5432),
            otherwise: Joi.number().default(3306)
        }),

        DB_RETRIES: Joi.number().integer().min(0).optional().default(3)
    }),

    initDB: async () => {
        let retries = process.env.DB_RETRIES;

        do {
            try {
                db = await connectToDB();
                return;
            } catch (e) {
                console.error(`Failed to connect to DB: ${e}`)
                if (retries >= 2 || process.env.DB_RETRIES == 0) {
                    console.log(`Attempting another connection after 3s`);
                    await new Promise(res => setTimeout(res, 3000));
                }
            }
        } while (process.env.DB_RETRIES == 0 || --retries > 0);

        throw new Error("Failed to connect to DB");
    },

    query: (table = process.env.DB_TABLE) => db(table),
    db: () => db
};
