'use strict';

const Dayjs = require('dayjs');
const Joi = require('joi');
const Rfr = require('rfr');

const Common = Rfr('/shared/common');
const ComSrv = Rfr('/server/comsrv');

const Db = Rfr('/server/db');


const dispToNumber = function(disp) {
    disp = disp.toUpperCase();
    if (disp === 'ANSWERED') {
        return Common.resAnswered;
    }
    if (disp === 'NO ANSWER') {
        return Common.resNoAnswer;
    }
    if (disp === 'FAILED') {
        return Common.resFailed;
    }
    if (disp === 'BUSY') {
        return Common.resBusy;
    }
    if (disp === 'CANCELLED') {
        return Common.resCancelled;
    }
    return Common.resOther;
}

const moveSingleRecord = async function(r) {
    try {
        await Db.db().transaction(async trx => {

            const n = {
                calldate: Dayjs(r.calldate),
                source: Common.uglifyPhone(r.src),
                destination: (r.actualdst ? Common.uglifyPhone(r.actualdst) : Common.uglifyPhone(r.dst)),
                uniqueid: (r.actualuniqueid ? r.actualuniqueid : r.uniqueid),
                callduration: (r.actualbillsec ? r.actualbillsec : r.billsec),
                totalduration: r.duration,
                ivr: (r.ivr || 0)
            };

            if (r.actualdst2 && r.ivr === 3) {
                n.destination = Common.uglifyPhone(r.actualdst2);
            }

            if (r.startedat && r.end) {
                const actualCD = Math.ceil(r.end - parseInt(r.startedat, 10));
                if (Number.isSafeInteger(actualCD)) {
                    n.callduration = actualCD;
                    console.log('changing CD');
                }
            }

            n.calltype = Common.getCallType(n.source, n.destination);

            if (r.actualdisposition) {
                n.callresult = dispToNumber(r.actualdisposition);
            } else if (r.ivr === 1 || r.ivr === 2) {
                n.callresult = Common.resCancelled;
            } else if (r.disposition === 'ANSWERED' && !r.startedat) {
                n.callresult = Common.resNoAnswer;
            } else {
                n.callresult = dispToNumber(r.disposition);
            }

            if (n.callresult === Common.resCancelled || n.callresult === Common.resNoAnswer) {
                n.callduration = 0;
            }

            const maxDaily = await trx.max('dailyid').from('ptable')
                .where('calldate', '>=', Dayjs(r.calldate).startOf('day'))
                .andWhere('calldate', '<=', Dayjs(r.calldate).endOf('day')).first();
            n.dailyid = (!maxDaily || !maxDaily.max) ? 1 : (maxDaily.max + 1);

            const maxCT = await trx.max('dailyct').from('ptable')
                .where('calldate', '>=', Dayjs(r.calldate).startOf('day'))
                .andWhere('calldate', '<=', Dayjs(r.calldate).endOf('day'))
                .andWhere('calltype', '=', n.calltype).first();
            n.dailyct = (!maxCT || !maxCT.max) ? 1 : (maxCT.max + 1);

            await trx.insert(n).into('ptable');
            ComSrv.debug('Inserted record with UID: ' + n.uniqueid);
        });
    } catch (e) {
        console.error('Failed to insert record to PTable: ' + e);
    }
}



const createPTable = async function() {
    const hasTable = await Db.db().schema.hasTable('ptable');
    if (!hasTable) {
        console.log('PTable is missing - will create');

        await Db.db().schema.createTable('ptable', t => {
            t.increments('id').primary();
            t.timestamp('calldate');
            t.integer('calltype');
            t.integer('callresult');
            t.string('source');
            t.string('destination');
            t.string('uniqueid');
            t.integer('callduration');
            t.integer('totalduration');
            t.integer('dailyid');
            t.integer('dailyct');
            t.string('comment');
            t.integer('ivr');
        });

        console.log('PTable created');
    }
};

const moveToPTable = async function() {
    await createPTable();

    const rec = await Db.db().select('*').from(process.env.DB_TABLE)
    .where(function() {
        this.where(function() {
            this.whereNotNull('uniqueid')
            .whereNull('actualuniqueid')
            .whereNotIn('uniqueid', function() {
                this.select('uniqueid').from('ptable');
            })
        })
        .orWhere(function() {
            this.whereNotNull('actualuniqueid')
            .whereNotIn('actualuniqueid', function() {
                this.select('uniqueid').from('ptable');
            })
        })
    })
    .where('duration', '>', 0)
    .whereNotNull('realcall')
    .where('realcall', '>=', 1)
    .whereNot(function() {
        this.whereNotNull('ivr')
        .where('ivr', '=', 3)
        .whereNull('startedat')
    })
    .orderBy('calldate', 'asc');

    if (rec && rec.length) {
        ComSrv.debug('Importing ' + rec.length + ' new records to PTable');
        for (const r of rec) {
            await moveSingleRecord(r);
        }
    }

    setTimeout(moveToPTable, process.env.PTABLE_INTERVAL * 1000);
};


const initPTable = async function() {
    await moveToPTable();
    ComSrv.debug('PTable initialized');
};


module.exports = {
    initPTable: initPTable,

    config: Joi.object({
        PTABLE_INTERVAL: Joi.number().min(1).max(300).default(10).optional()
    })
};
