const uid = require('gen-uid');
require('linqjs');

const thirdPartyDB = class thirdPartyDB {
    constructor({db, moment, config, utils, logger} = {}) {
        this.db = db;
        this.moment = moment;
        this.config = config;
        this.utils = utils;
        this._sequelize = this.db._sequelize;
        this.thirdPartyDB = this.db.ThirdPartyFiles;
        this.customerKeys = this.db.CustomerKeys;
        this.logger = logger;
        this.checkTimer = 5000;
        this.eventTypes = {
            dataEmpty: 'dataEmpty'
        };
    }

    async InsertThirdPartyFiles(data) {
        this.logger.ThirdParty(`inserting ${data.length} third party files on third party db`);
        let thirdParty = data.select((c) => {
            return {
                OriginalName: c.FileName,
                FileName: uid.v4(c.FileName),
                FileSize: c.FileSize,
                customerID: c.customerID
            }
        });
        data = null;
        let thirdPartyFilesInDB = (await this.thirdPartyDB.findAll()).select((i) => i.dataValues);
        let customerKeys = (await this.customerKeys.findAll()).select((i) => i.dataValues);
        if(thirdPartyFilesInDB) {
            this.logger.ThirdParty('new third party files data in db, comparing with server');
            let compare = await this.compareThirdParty(thirdParty, thirdPartyFilesInDB);
            if (compare) {
                this.logger.ThirdParty('skipping insert, data is same');
                return;
            } else {
                // data is different, destroying old and inserting data.
                await this.thirdPartyDB.destroy({where: {customerID: {gt: 0}}});
                this.logger.ThirdParty('we have new third party files from server, inserting');
                let valid = [];
                thirdParty.forEach((c) => {
                    customerKeys.forEach(d => {
                        if (c.customerID == d.customerID) {
                            valid.push(c);
                        }
                    })
                });
                if (valid.length > 0) {
                    await this.thirdPartyDB.bulkCreate(valid);
                }
                return;
            }
        } else {
            this.logger.ThirdParty('we dont have any third party files data on db, inserting');
            let valid = [];
            thirdParty.forEach((c) => {
                customerKeys.forEach(d => {
                    if (c.customerID == d.customerID) {
                        valid.push(c);
                    }
                })
            });
            if (valid.length > 0) {
                await this.thirdPartyDB.bulkCreate(valid);
            }
            return;
        }
    }

    async InsertCustomerKeys(data) {
        if (!data || data.length == 0) {
            await this.customerKeys.destroy({where: {customerID: {gt: 0}}});
            await this.thirdPartyDB.destroy({where: {customerID: {gt: 0}}});
            this.logger.ThirdParty('data has no items, removing third party and customer key tables from db');
            this.emit(this.eventTypes.dataEmpty);
            return;
        }
        this.logger.ThirdParty(`inserting ${data.length} customer key data on third party db`);
        let cust = [];
        let cnt = 1;
        data.forEach((c) => {
                c.ID = cnt++;
                cust.push(c)
        });
        let customerKey = cust.select((c) => {
            return {
                customerID: c.ThirdPartyID,
                ID: c.ID,
                Name: c.CompanyName,
                AuthKey: c.ApiKey,
                createdDate: c.CreatedDate
            }
        });
        data = null;
        cust = null;
        let customerKeysDb = (await this.customerKeys.findAll()).select((i) => i.dataValues);
        if (customerKeysDb) {
            this.logger.ThirdParty('new customer key data in db, comparing with server');
            let compare = await this.compareCustomer(customerKey, customerKeysDb);
            if (compare) {
                this.logger.ThirdParty('skipping insert, data is same');
                return;
            } else {
                await this.customerKeys.destroy({where: {customerID: {gt: 0}}});
                await this.thirdPartyDB.destroy({where: {customerID: {gt: 0}}});
                this.logger.ThirdParty('we have new customer keys from server, inserting');
                await this.customerKeys.bulkCreate(customerKey);
                return;
            }
        } else {
            this.logger.ThirdParty('we dont have any customer keys data on db, inserting');
            await this.customerKeys.bulkCreate(customerKey);
        }
    }

    async getCustomerKeysDetails() {
        let info = await (await this.customerKeys.findAll()).select((i) => i.dataValues);
        let customerkeysDetails = [];
        await info.forEach(c => customerkeysDetails.push(c));
        info = null;
        return customerkeysDetails;
    }

    async getThirdPartyFilesWithCustomerDetails() {
        let info = await (await this.thirdPartyDB.findAll({include: ['CustomerKeys']}));
        let details = [];
        await info.forEach(c => c.CustomerKeys.forEach(d => details.push(d.dataValues)));
        return details;
    }

    async compareCustomer(server, db) {
        if (server.length != db.length) return false;
        let o1 = server, o2 = db;
        for (let i = 0; i < db.length; i++) {
            if (!(
                o1[i].ID === o2[i].ID &&
                o1[i].Name === o2[i].Name &&
                o1[i].AuthKey === o2[i].AuthKey)

            ) {
                return false;
            }
        }
        return true;
    }

    async compareThirdParty(server, db) {
        if (server.length != db.length) return false;
        let o1 = server, o2 = db;
        for (let i = 0; i < db.length; i++) {
            if (!(
                o1[i].FileID === o2[i].FileID &&
                o1[i].OriginalName === o2[i].OriginalName) &&
                o1[i].FileSize === o2[i].FileSize &&
                o1[i].customerID === o2[i].customerID

            ) {
                return false;
            }
        }
        return true;
    }
};

const util = require('util'), EventEmitter = require('events').EventEmitter;
util.inherits(thirdPartyDB, EventEmitter);
module.exports = thirdPartyDB;
