'use strict';

var async = require('async');
var fs = require('graceful-fs');
var glob = require('glob');
var path = require('path');

var config = require('../config');
var Logger = require('../logger');

function applyPatch(db, file, callback) {
    Logger.tag('database', 'migration').info('Checking if patch need to be applied: %s', file);

    fs.readFile(file, function (err, contents) {
        if (err) {
            return callback(err);
        }

        var version = path.basename(file, '.sql');

        db.get('SELECT * FROM schema_version WHERE version = ?', version, function (err, row) {
            if (err) {
                return callback(err);
            }

            if (row) {
                // patch is already applied. skip!
                Logger.tag('database', 'migration').info('Patch already applied, skipping: %s', file);
                return callback(null);
            }

            var sql = 'BEGIN TRANSACTION;\n' +
                      contents.toString() + '\n' +
                      'INSERT INTO schema_version (version) VALUES (\'' + version + '\');\n' +
                      'END TRANSACTION;';

            db.exec(sql, function (err) {
                if (err) {
                    return callback(err);
                }

                Logger.tag('database', 'migration').info('Patch successfully applied: %s', file);

                callback(null);
            });
        });
    });
}

function applyMigrations(db, callback) {
    Logger.tag('database', 'migration').info('Migrating database...');

    var sql = 'BEGIN TRANSACTION; CREATE TABLE IF NOT EXISTS schema_version (\n' +
              '    version VARCHAR(255) PRIMARY KEY ASC,\n' +
              '    applied_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL\n' +
              '); END TRANSACTION;';
    db.exec(sql, function (err) {
        if (err) {
            return callback(err);
        }

        glob(__dirname + '/patches/*.sql', function (err, files) {
            if (err) {
                return callback(err);
            }

            async.eachSeries(
                files,
                function (file, fileCallback) {
                    applyPatch(db, file, fileCallback);
                },
                callback
            );
        });
    });
}

module.exports = {
    init: function (callback) {
        var SQLite3 = require('sqlite3');

        var file = config.server.databaseFile;
        Logger.tag('database').info('Setting up database: %s', file);

        var db;
        try {
            db = new SQLite3.Database(file);
        }
        catch (error) {
            Logger.tag('database').error('Error initialzing database:', error);
            throw error;
        }

        db.on('profile', function (sql, time) {
            Logger.tag('database').profile('[%sms]\t%s', time, sql);
        });

        applyMigrations(db, function (err) {
            if (err) {
                Logger.tag('database').error('Error migrating database:', err);
                throw err;
            }

            angular.module('ffffng').factory('Database', function () {
                return db;
            });

            callback();
        });
    }
};