const db = require('../database.js');

const TABLE_NAME = "accountConfig";

function AccountConfigManager() {
}

AccountConfigManager.prototype.defaultForAccount = function(id, cb) {
    var self = this;
    db.database.queryFirst(TABLE_NAME, { accountId: id, serviceId: null, deviceId: null }, (err, result) => {
        cb(result ? self.fromDb(result) : null);
    });
};

AccountConfigManager.prototype.fromAccountId = function(id, cb) {
    var self = this;
    db.database.query(TABLE_NAME, { accountId: id }, (err, result) => {
        if (!result)
            cb(null);
        let accConfigs = [];
        result.forEach((res) => {
            accConfigs.push(self.fromDb(res));
        });
        cb(accConfigs);
    });
};

AccountConfigManager.prototype.addToConfig = function(accountId, service, device, newConfig, now, cb) {
    var self = this;
    db.database.query(TABLE_NAME, { accountId: accountId }, (err, result) => {
        // Lazy create config for [ service, device ]
        if (result)
            for (var i =0, nbResults = result.length; i < nbResults; i++) {
                if (result[i].serviceId === service && result[i].deviceId === device) {
                    let conf = self.fromDb(result[i]);
                    conf.merge(newConfig, now);
                    self.save(conf, cb);
                    return;
                }
            }
        let conf = new AccountConfigWrapper();
        conf.accountId = accountId;
        conf.serviceId = service;
        conf.deviceId = device;
        conf.merge(newConfig, now);
        self.save(conf, cb);
    });
};

AccountConfigManager.prototype.fromAccountIdAndVersion = function(id, v, cb) {
    var self = this;
    db.database.query(TABLE_NAME, { accountId: id }, (err, result) => {
        if (!result)
            cb(null);
        for (var i =0, nbConfig = result.length; i < nbConfig; i++) {
            if (result[i].modified > v) {
                var configs = [];
                for (i =0; i < nbConfig; i++) {
                    configs.push(self.fromDb(result[i]));
                }
                cb(configs);
                return;
            }
        }
        cb(null);
    });
};

AccountConfigManager.prototype.newConfigFor = function(account) {
    var conf = new AccountConfigWrapper();
    conf.dirty = true;
    conf.accountId = account.id;
    return conf;
};

AccountConfig.prototype.addService = function(serviceType, serviceName, serviceId) {
    if (!this.services[serviceType])
        this.services[serviceType] = {};
    this.services[serviceType][serviceId] = serviceName;
};

AccountConfig.prototype.merge = function(configBlob) {
    let modified = false;

    if (configBlob["emojiProvider"] !== undefined && configBlob["emojiProvider"] !== this.emojiProvider) {
        this.emojiProvider = configBlob["emojiProvider"];
        modified = true;
    }
    if (configBlob["displayAvatar"] !== undefined && configBlob["displayAvatar"] !== this.displayAvatar) {
        this.displayAvatar = configBlob["displayAvatar"];
        modified = true;
    }
    if (configBlob["colorfulNames"] !== undefined && configBlob["colorfulNames"] !== this.colorfulNames) {
        this.colorfulNames = configBlob["colorfulNames"];
        modified = true;
    }
    if (configBlob["scrollAvatars"] !== undefined && configBlob["scrollAvatars"] !== this.scrollAvatars) {
        this.scrollAvatars = configBlob["scrollAvatars"];
        modified = true;
    }
    if (configBlob["autoExpandAttachments"] !== undefined && configBlob["autoExpandAttachments"] !== this.autoExpandAttachments) {
        this.autoExpandAttachments = configBlob["autoExpandAttachments"];
        modified = true;
    }
    return modified;
};

AccountConfigManager.prototype.fromId = function(id, cb) {
    var self = this;
    db.database.queryFirst(TABLE_NAME, { id: id }, (err, result) => {
        cb(self.fromDb(result));
    });
};

AccountConfigManager.prototype.fromDb = function(dbResult) {
    if (!dbResult)
        return null;
    return new AccountConfigWrapper(dbResult);
};

function AccountConfigWrapper(dbResult) {
    this.id;

    this.accountId;
    this.serviceId; // Can be null, or a serviceId
    this.deviceId; // Can be null, or a deviceId

    this.config = new AccountConfig();
    this.modified; // modified ts

    if (dbResult) {
        this.id = dbResult.id;

        this.accountId = dbResult.accountId;
        this.serviceId = dbResult.serviceId;
        this.deviceId = dbResult.deviceId;

        this.config.fromDb(dbResult.config);
        this.modified = dbResult.modified;
        this.dirty = false;
    } else {
        this.id = null;

        this.accountId = null;
        this.serviceId = null;
        this.deviceId = null;

        this.modified = Date.now();

        this.dirty = true;
    }
}

AccountConfigWrapper.prototype.toDb = function() {
    return {
        accountId: this.accountId,
        serviceId: this.serviceId,
        deviceId: this.deviceId,
        config: this.config.toDb(),
        modified: this.modified
    };
};

AccountConfigWrapper.prototype.merge = function(configBlob, now) {
    if (this.config.merge(configBlob)) {
        this.edit(now);
        return true;
    }
    return false;
};

AccountConfigManager.prototype.save = function(account, cb) {
    if (!account.id) {
        // insert and save id
        var data = account.toDb();
        data.id = null;
        db.database.insert(TABLE_NAME, data, (newId) => {
            account.id = newId;
            account.dirty = false;
            if (cb) cb(account);
        });
    } else if (account.dirty) {
        // update
        db.database.update(TABLE_NAME, account.id, account.toDb(), () => {
            account.dirty = false;
            if (cb) cb(account);
        });
    } else {
        // not changed
        if (cb) cb(account);
    }
};

AccountConfigWrapper.prototype.expose = function() {
    return {
        service: this.serviceId,
        device: this.deviceId,
        config: this.config.toDb()
    };
};

AccountConfigWrapper.prototype.edit = function(now) {
    this.dirty = true;
    this.modified = Math.max(this.modified, now || Date.now());
    return this;
};

function AccountConfig() {
    this.services = {};
}

AccountConfig.prototype.toDb = function() {
    return JSON.stringify({
        services: this.services,
        emojiProvider: this.emojiProvider,
        displayAvatar: this.displayAvatar,
        colorfulNames: this.colorfulNames,
        scrollAvatars: this.scrollAvatars,
        autoExpandAttachments: this.autoExpandAttachments
    });
};

AccountConfig.prototype.fromDb = function(dbObj) {
    dbObj = JSON.parse(dbObj);
    this.services = dbObj.services || [];
    this.emojiProvider = dbObj.emojiProvider;
    this.displayAvatar = dbObj.displayAvatar;
    this.colorfulNames = dbObj.colorfulNames;
    this.scrollAvatars = dbObj.scrollAvatars;
    this.autoExpandAttachments = dbObj.autoExpandAttachments;
};

module.exports.accountConfigManager = new AccountConfigManager();

module.exports.updateTable = function(dbObject, currentVersion, cb) {
    if (!currentVersion) {
        console.info("Creating table " +TABLE_NAME);
        dbObject.run('CREATE TABLE IF NOT EXISTS `' +TABLE_NAME +'` ('
            +"`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,"
            +"`accountId` STRING NOT NULL,"
            +"`serviceId` STRING,"
            +"`deviceId` STRING,"
            +"`config` STRING NOT NULL,"
            +"`modified` INT NOT NULL"
            +');CREATE INDEX accconfigbyaccount ON ' +TABLE_NAME +'(accountId); CREATE UNIQUE INDEX accconfigUniq ON ' +TABLE_NAME +'(accountId, serviceId, deviceId)', cb);
    } else {
        cb(null);
    }
};

