/*
    ! /database/pools.js
    ? The main database pool (connection) manager
*/

// % imports
import mariadb from 'mariadb';

// % database credentials mapping
const CREDENTIALS_MAP = {
    read: { user: process.env.DB_READ_USER, pass: process.env.DB_READ_PASS },
    write: { user: process.env.DB_WRITE_USER, pass: process.env.DB_WRITE_PASS },
    delete: { user: process.env.DB_DELETE_USER, pass: process.env.DB_DELETE_PASS },
    backup: { user: process.env.DB_BACKUP_USER, pass: process.env.DB_BACKUP_PASS }
}

// $ get database credentials
function getCredentials(protocol = 'read') {
   const key = String(protocol).toLowerCase();
   return CREDENTIALS_MAP[key] ?? CREDENTIALS_MAP.read;
}

// = pool manager class
class PoolManager {
    constructor() {
        this.pools = new Map();
    }

    // $ function to add a connection
    async add(config) {
        // ~ check if this pool is already existing → then return
        if (this.pools.has(config.name)) {
            return { pool: this.pools.get(config.name), connStat: true };
        }

        // ~ get database credentials by protocol
        const { user, pass } = getCredentials(config.protocol);

        // ~ create the mariadb pool
        const pool = mariadb.createPool({
            host: config.address,
            port: Number(process.env.DB_CONN_PORT),
            user,
            password: pass,
            database: config.database,
            waitForConnections: true,
            connectionLimit: 5,
            queueLimit: 0,
            enableKeepAlive: true,
            keepAliveInitialDelay: 10000
        });
        
        // ~ add the pool to the map
        this.pools.set(config.name, pool);

        // ~ return the pool
        return { pool, connStat: true };
    }

    // $ function to remove a connection
    async remove(name) {
        if (this.pools.has(name)) {
            const pool = this.pools.get(name);
            await pool.end();
            this.pools.delete(name);
        }
        return { connStat: false };
    }

    // $ function to get the status of a connection
    async status(name) {
        if (this.pools.has(name)) {
            try {
                const pool = this.pools.get(name);
                await pool.query('SELECT 1');
                return { pool, connStat: true };
            } catch(err) {
                return { connStat: false, msg: err }
            }
        } else {
            return { connStat: false };
        }
    }
}

// $ export the pool manager
export default new PoolManager();