"use strict";
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
    result["default"] = mod;
    return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const path = __importStar(require("path"));
const typeorm_1 = require("typeorm");
const helpers_1 = require("../helpers");
const access_fields_1 = __importDefault(require("./entities/access-fields"));
exports.AccessField = access_fields_1.default;
const accesses_1 = __importDefault(require("./entities/accesses"));
exports.Access = accesses_1.default;
const accounts_1 = __importDefault(require("./entities/accounts"));
exports.Account = accounts_1.default;
const alerts_1 = __importDefault(require("./entities/alerts"));
exports.Alert = alerts_1.default;
const budgets_1 = __importDefault(require("./entities/budgets"));
exports.Budget = budgets_1.default;
const categories_1 = __importDefault(require("./entities/categories"));
exports.Category = categories_1.default;
const settings_1 = __importDefault(require("./entities/settings"));
exports.Setting = settings_1.default;
const transactions_1 = __importDefault(require("./entities/transactions"));
exports.Transaction = transactions_1.default;
const users_1 = __importDefault(require("./entities/users"));
exports.User = users_1.default;
const log = helpers_1.makeLogger('models/index');
function makeOrmConfig() {
    let ormConfig;
    // Keep this switch in sync with ../config.ts!
    switch (process.kresus.dbType) {
        case 'sqlite':
            helpers_1.assert(process.kresus.sqlitePath !== null, 'missing db path in server/models');
            ormConfig = {
                type: 'sqlite',
                database: process.kresus.sqlitePath,
                logging: process.kresus.dbLog
            };
            break;
        case 'postgres':
        case 'mysql':
        case 'mariadb':
            helpers_1.assert(typeof process.kresus.dbHost === 'string', 'missing db host in server/models');
            helpers_1.assert(typeof process.kresus.dbPort === 'number', 'missing db port in server/models');
            helpers_1.assert(typeof process.kresus.dbUsername === 'string', 'missing db username in server/models');
            helpers_1.assert(typeof process.kresus.dbPassword === 'string', 'missing db password in server/models');
            helpers_1.assert(typeof process.kresus.dbName === 'string', 'missing db name in server/models');
            ormConfig = {
                type: process.kresus.dbType,
                host: process.kresus.dbHost,
                port: process.kresus.dbPort,
                username: process.kresus.dbUsername,
                password: process.kresus.dbPassword,
                database: process.kresus.dbName,
                logging: process.kresus.dbLog
            };
            break;
        default:
            helpers_1.panic('unexpected db type in server/models');
    }
    return ormConfig;
}
async function setupOrm() {
    const ormConfig = Object.assign(makeOrmConfig(), {
        // Automatically run migrations.
        migrationsRun: true,
        // Entity models.
        entities: [path.join(__dirname, 'entities/*')],
        // Migration files.
        migrations: [path.join(__dirname, 'migrations/*')],
        // Automatically synchronize the database schema on startup. Very
        // unsafe, use only to look at queries generated by the ORM.
        synchronize: false
    });
    await typeorm_1.createConnection(ormConfig);
}
exports.setupOrm = setupOrm;
async function initModels(root, cozyDbName) {
    await setupOrm();
    let userId;
    if (process.kresus.providedUserId !== null) {
        userId = process.kresus.providedUserId;
        // Check that the user actually exists already.
        const user = await users_1.default.find(userId);
        if (!user) {
            throw new Error(`The user with provided ID ${userId} doesn't exist. Did you run "kresus create:user" first?`);
        }
    }
    else {
        // Create default user.
        let user;
        const users = await users_1.default.all();
        if (!users.length) {
            const { login } = process.kresus.user;
            helpers_1.assert(!!login, 'There should be a default login set!');
            log.info('Creating default user...');
            user = await users_1.default.create({ login });
        }
        else if (users.length > 1) {
            throw new Error('Several users in database but no user ID provided. Please provide a user ID');
        }
        else {
            user = users[0];
        }
        userId = user.id;
    }
    process.kresus.user.id = userId;
    log.info(`User has id ${userId}`);
    // Try to migrate the older Pouchdb database, if it's not been done yet.
    const didMigrate = await settings_1.default.findOrCreateDefaultBooleanValue(userId, 'migrated-from-cozydb');
    log.info(`Checking if the migration from CozyDB is required... ${didMigrate ? 'no' : 'yes'}`);
    if (!didMigrate) {
        // eslint-disable-next-line import/no-cycle, @typescript-eslint/no-var-requires
        const all = require('../controllers/all');
        // eslint-disable-next-line @typescript-eslint/no-var-requires
        const exportCozyDb = require('kresus-export-cozydb');
        const options = Object.assign({}, { root, dbName: cozyDbName });
        log.info('Migrating from CozyDB...');
        try {
            const world = await exportCozyDb.run(options);
            await all.importData(userId, world);
            log.info('Migrating from CozyDB done!');
            await settings_1.default.updateByKey(userId, 'migrated-from-cozydb', true);
        }
        catch (err) {
            log.error(`Unable to migrate from CozyDB: ${err.message}
${err.stack}`);
            log.info('Removing partially imported data...');
            // Remove all associated data, except for settings; they'll be
            // properly clobbered during the next successful attempt.
            await access_fields_1.default.destroyAll(userId);
            await accesses_1.default.destroyAll(userId);
            await accounts_1.default.destroyAll(userId);
            await alerts_1.default.destroyAll(userId);
            await categories_1.default.destroyAll(userId);
            await budgets_1.default.destroyAll(userId);
            await transactions_1.default.destroyAll(userId);
            log.info('Removing partially imported data: done!');
        }
    }
}
exports.initModels = initModels;
