"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateDBML = exports.initSequelizeModule = exports.getSequelize = exports.modelsSync = exports.addDtosToSwagger = exports.addModelsToSequelize = exports.loadPath = exports.dbInit = void 0;
const sequelize_typescript_1 = require("sequelize-typescript");
const fs_1 = __importDefault(require("fs"));
const core_1 = require("@asapjs/core");
require("reflect-metadata");
let container = null;
const models = [];
const dtos = [];
const dbInit = (config) => __awaiter(void 0, void 0, void 0, function* () {
    const sequelize = new sequelize_typescript_1.Sequelize(config);
    container = sequelize;
    sequelize
        .authenticate()
        .then(() => {
        core_1.logger.info('@sequelize :: Database connected.');
    })
        .catch((err) => __awaiter(void 0, void 0, void 0, function* () {
        // if error occured for database is not exist, create it
        if (err.name == 'SequelizeConnectionError' &&
            err.original.code === 'ER_BAD_DB_ERROR' &&
            err.original.sqlMessage.startsWith('Unknown database')) {
            const databaseName = config.database;
            core_1.logger.error(`@sequelize :: Database ${databaseName} has not craeted. Run auto database create process`);
            const temp_config = Object.assign({}, config);
            temp_config.database = undefined;
            // create temp sequelize connection
            const sequelize_temp = new sequelize_typescript_1.Sequelize(temp_config);
            sequelize_temp.authenticate().then(() => {
                core_1.logger.info('@sequelize(temp_session) :: Database connected.');
            });
            // if database is not exist, run create database query
            yield sequelize_temp.query(`CREATE DATABASE IF NOT EXISTS \`${databaseName}\`;`).then(() => {
                core_1.logger.info(`@sequelize(temp_session) :: Database ${databaseName} Create Successfully`);
            });
            sequelize_temp.close().then(() => {
                core_1.logger.info(`@sequelize(temp_session) :: Release temp session successfully`);
            });
            sequelize.authenticate().then(() => {
                core_1.logger.info('@sequelize :: Database Reconnect Successfully');
            });
        }
        else {
            core_1.logger.error('@sequelize :: Unable to connect to the database:\n', err);
        }
    }));
    core_1.logger.info('@sequelize :: database initalize.');
    return sequelize;
});
exports.dbInit = dbInit;
const loadPath = (path, subPath) => __awaiter(void 0, void 0, void 0, function* () {
    const files = yield fs_1.default.readdirSync(path + subPath, { withFileTypes: true });
    // const extension = process.env.NODE_ENV === 'production' ? 'js' : 'ts';
    const extension = 'js';
    for (const file of files) {
        if (file.isDirectory()) {
            yield (0, exports.loadPath)(path, `${subPath}/${file.name}`);
        }
        else if (file.name.includes(`Table.${extension}`) && file.name.endsWith('map') === false) {
            models.push(require(`${path}/${subPath}/${file.name}`).default);
        }
        else if (file.name.includes(`Dto.${extension}`) && file.name.endsWith('map') === false) {
            const dto = require(`${path}/${subPath}/${file.name}`).default;
            if (dto) {
                dtos.push(dto);
            }
        }
    }
});
exports.loadPath = loadPath;
const addModelsToSequelize = () => __awaiter(void 0, void 0, void 0, function* () {
    container.addModels(models);
    core_1.logger.info('@sequelize :: add models to sequelize instance.');
});
exports.addModelsToSequelize = addModelsToSequelize;
const addDtosToSwagger = () => __awaiter(void 0, void 0, void 0, function* () {
    yield Promise.all(dtos.map((Dto) => {
        const dto = new Dto();
        if (!(dto === null || dto === void 0 ? void 0 : dto.init)) {
            core_1.logger.warn(`@sequelize :: ${dto.constructor.name} is not a valid dto class. It should extends with ExtendableDto.`);
        }
        else {
            dto === null || dto === void 0 ? void 0 : dto.init();
        }
    }));
    core_1.logger.info('@sequelize :: add dto to swagger schemas.');
});
exports.addDtosToSwagger = addDtosToSwagger;
const modelsSync = () => __awaiter(void 0, void 0, void 0, function* () {
    yield container.sync({ alter: { drop: false } });
    core_1.logger.info('@sequelize :: models sync finished');
    return true;
});
exports.modelsSync = modelsSync;
const getSequelize = () => container;
exports.getSequelize = getSequelize;
const initSequelizeModule = (dirname) => __awaiter(void 0, void 0, void 0, function* () {
    const dbContainer = yield (0, exports.dbInit)((0, core_1.getConfig)().db);
    yield (0, exports.loadPath)(dirname, '');
    yield (0, exports.addModelsToSequelize)();
    yield (0, exports.addDtosToSwagger)();
    return dbContainer;
});
exports.initSequelizeModule = initSequelizeModule;
const generateDBML = () => __awaiter(void 0, void 0, void 0, function* () { });
exports.generateDBML = generateDBML;
//# sourceMappingURL=index.js.map