const ejs = require('ejs');
const fs = require('fs-extra');
const SqlString = require('sqlstring');

module.exports = class Exporter {
    constructor(objectType, replace) {
        Object.assign(this, {
            objectType,
            replace
        });
    }

    async init() {
        const templateDir = `${__dirname}/../exporters/${this.objectType}`;
        this.sql = await fs.readFile(`${templateDir}.sql`, 'utf8');

        const templateFile = await fs.readFile(`${templateDir}.ejs`, 'utf8');
        this.template = ejs.compile(templateFile);
        this.attrs = require(`${templateDir}.js`);
    }

    async query(conn, schema, name) {
        const ops = [];
        function addOp(col, value) {
            ops.push(conn.format('?? = ?', [col, value]));
        }
        if (schema)
            addOp(this.attrs.schemaCol, schema);
        if (name)
            addOp(this.attrs.nameCol, name);

        const filter = {
            toSqlString() {
                return ops.join(' AND ');
            }
        }

        const [res] = await conn.query(this.sql, [filter]);
        return res;
    }

    format(params) {
        const {attrs} = this;
        params = Object.assign({}, attrs.defaults, params)
        const data = {params};

        if (attrs.formatter)
            attrs.formatter(params);

        if (attrs.escapeCols)
        for (const escapeCol of attrs.escapeCols) {
            if (params[escapeCol])
                params[escapeCol] = SqlString.escape(params[escapeCol])
        }

        const split = params.definer.split('@');
        data.definer =
            SqlString.escapeId(split[0], true) + '@' +
            SqlString.escapeId(split[1], true);

        data.name =
            SqlString.escapeId(params.schema, true) + '.' +
            SqlString.escapeId(params.name, true);

        const objectType = this.objectType.toUpperCase();
        const delimiter = '$$';
        const replace = `CREATE OR REPLACE`;

        let create;
        if (this.replace) {
            create = `DELIMITER ${delimiter}\n${replace}`
        } else {
            create =
                 `DROP ${objectType} IF EXISTS ${data.name};\n`
                +`DELIMITER ${delimiter}\n`
                +`CREATE`;
        }

        data.createOrReplace = `${replace} DEFINER=${data.definer}`
        data.begin = `${create} DEFINER=${data.definer}`;
        data.typeAndName = `${objectType} ${data.name}`;
        data.end = `${delimiter}\nDELIMITER ;`;

        return this.template(data);
    }
}