
var myArgs = process.argv.slice(2);

if ( myArgs.length < 2 ) {
    console.log("Missing args", myArgs);
    process.exit(0);
}

const IS_REAL = myArgs[1] !== 'test';
const WARNING_DAYS = 1;

// ---

const db = require('qmi-cloud-common/mongo');
const sendEmail = require("qmi-cloud-common/send-email");
const moment = require('moment');
const cli = require('qmi-cloud-common/cli');

function timeRunningIs24x7(p) {
    let runningFromTime = p.runningFrom? new Date(p.runningFrom).getTime() : new Date(p.created).getTime();
    let totalRunningFromTime = Math.abs(new Date().getTime() - runningFromTime);
    let duration = moment.duration(totalRunningFromTime);
    p.duration = {
        hours: Math.floor(duration.asHours()),
        complete: Math.floor(duration.asDays()) +"d "+duration.hours()+"h "+duration.minutes()
    };
}

function timeRunningOnSchedule(p) {
    let runningFromTime = p.runningFrom? new Date(p.runningFrom).getTime() : new Date(p.created).getTime();
    let totalRunningTime = p.timeRunning*1000*60;
    let now = new Date();
    totalRunningTime = totalRunningTime + Math.abs(now.getTime() - runningFromTime);
    let duration = moment.duration(totalRunningTime);
    p.duration = {
        hours: Math.floor(duration.asHours()),
        complete: Math.floor(duration.asDays()) +"d "+duration.hours()+"h "+duration.minutes()
    };
}

function timeRunningOnSchedule2(p) {
    
    let startTimestamp = p.startDateOnSchedule? new Date(p.startDateOnSchedule).getTime() : 0;
    let endTimestamp = p.endDateOnSchedule? new Date(p.endDateOnSchedule).getTime() : 0;
    let totalTimeOnschedule = Math.abs(endTimestamp - startTimestamp);
    let duration = moment.duration(totalTimeOnschedule);
    p.duration = {
        hours: Math.floor(duration.asHours()),
        complete: Math.floor(duration.asDays()) +"d "+duration.hours()+"h "+duration.minutes()
    };
}

async function asyncForEach(array, callback) {
    for (let index = 0; index < array.length; index++) {
        await callback(array[index], index, array);
    }
}

async function init(type) {
    var cb;
    var filter = {
        "isDestroyed": false, 
        "isDeleted": false, 
        "statusVms": "Running",
        "vmImage": { "$exists": true },
        "vmImage.vm1":  { "$exists": true }
    };
    if ( type === "warning" ) {
        filter.pendingNextAction = { $ne: "stopVms" };
        cb = doSendEmailWarning;
    } else if ( type === "exec" ) {
        filter.pendingNextAction = "stopVms";
        cb = doStop;
    } else {
        console.log("Invalid 'type'. Do nothing.");
        return;
    }

    let provisions = await db.provision.get(filter);

    await asyncForEach(provisions.results, async function(p)  {
        //Only if 24x7
        let typeSchedule = "24x7";
        let periodDays = p._scenarioDoc.allowed24x7RunningDays;
        if ( !p.schedule || p.schedule.is24x7 ) {
            // 24x7
            timeRunningIs24x7(p);
            periodDays = p._scenarioDoc.allowed24x7RunningDays;
        } else if ( p.schedule && !p.schedule.is24x7 ) { 
            // OnSchedule      
            timeRunningOnSchedule2(p);
            typeSchedule = 'OnSchedule';
            periodDays = p._scenarioDoc.allowedOnScheduleRunningDays;
        }
        let limit;
        if ( type === "warning" ) {
            limit = 24*(periodDays-WARNING_DAYS); 
        } else if ( type === "exec" ) {
            limit = 24*periodDays;
        }
        if (!IS_REAL) {
            console.log(`${p._id} - (${typeSchedule}) - limit: ${limit} hs - actual duration: ${p.duration.hours} hs`);
        }
        if ( p.duration && p.duration.hours >= limit) {
            await cb(p, limit, typeSchedule);
        }
    });
}

const doSendEmailWarning = async function(p, limit, typeSchedule) {
    if ( p.pendingNextAction === 'stopVms') {
        console.log(`Warning email Stop already sent. Wait for pending action to complete.`);
    } else {
        let msg = `Send warning STOP email - ${p.user.displayName} (${p.user.upn}) about provision '${p._scenarioDoc.title}' (${p._id} - ${typeSchedule}) being 'Running' more than ${limit} hours, (exactly ${p.duration.complete})`;
        console.log(msg);
        if ( IS_REAL ) {
            db.event.add({ user: p.user._id, provision: p._id, type: 'vms.warning-stop' });
            await db.provision.update(p._id, {"pendingNextAction": "stopVms"});
            await db.notification.add({ provision: p._id.toString(), type: 'warningStop', message: msg }); 
            await sendEmail.sendWillStopIn24(p, p._scenarioDoc, Math.floor(limit/24), WARNING_DAYS);
        }       
    }  
};

const doStop = async function(p, limit, typeSchedule) {
    try {
        let msg = `VMs stopped - ${p.user.displayName} (${p.user.upn}) about provision '${p._scenarioDoc.title}' (${p._id} - ${typeSchedule}) being 'Running' more than ${limit} hours, (exactly ${p.duration.complete})`
        console.log(msg);

        if ( IS_REAL ) {   
            if (p.schedule){
                //Disable Divvy 
                await db.schedule.update(p.schedule._id, {"isStartupTimeEnable": false});
                await cli.updateVmsTags(p._id, {
                    "24x7": false,
                    "StartupTime": false,
                    "ShutdownTime": false
                });
            }
            //Stop VMs indefinitely
            db.event.add({ user: p.user._id, provision: p._id, type: 'vms.exec-stop' });
            await cli.deallocate(p._id, true); 
            await db.notification.add({ provision: p._id.toString(), type: 'stop', message: msg });
        }  
         
    } catch (error) {
        console.log("doStop Error", error);
        await db.provision.update(p._id, {"statusVms": "Error_Stopping"});
    }    
};

function check(type) {
    init(type).then(function(){
        db.mongoose.connection.close()
        process.exit(0);
        
    }).catch(function(e){
        db.mongoose.connection.close()
        console.log("Error", e);
        process.exit(0);
    });
}


// --------------------------------
switch (myArgs[0]) {
    case 'warning':
        check("warning");
        break;
    case 'exec':
        check("exec");
        break;
    default:
        console.log('Sorry, that is not something I know how to do.');
        process.exit(0);
}



