const db = require('qmi-cloud-common/mongo');
const path = require('path');
const PROJECT_PATH = process.env.PROJECT_PATH;
const tf = require("./docker/tf");
const azure = require("./docker/azure");
const sendEmail = require("qmi-cloud-common/send-email");
const barracuda = require("qmi-cloud-common/barracuda");

module.exports = async function(job) {
        
    var prov = await db.provision.update(job.data.id, {
        "status": "initializing", 
        "jobId": job.id, 
        "logFile": path.join('/logs', 'provision', `${job.data.id}.log`),
        "path": path.join(PROJECT_PATH, '..', 'qmi-cloud-provisions', `${job.data.scenario}_${job.data.id}`)
    });

    if ( !prov ) {
        console.log(`ProcessorApply# Error: Not found Provision object in Database (it should exist!), provisionId is: ${job.data.id}` );
        return Promise.reject({"success": false, "err": "Not found Provision object in Worker"});
    }

    var idProv = prov._id.toString();

    db.event.add({ user: prov.user._id, provision: prov._id, type: 'provision.init' });

    // TERRAFORM INIT
    return tf.init(prov)
    .then(async function(res) {
        if ( res.statusCode ===  1 ) {
            console.log(`ProcessorApply# Error at Terraform INIT for provision (${idProv})`);
            return Promise.reject({"success": false, "error": "Error at Terraform Init", provStatus: "error_init"}); 
        } else {
            // TERRAFORM PLAN
            return tf.plan(prov, job.data._scenario);
        }      
    } )
    .then( async function(res) {
        if ( res.statusCode === 1 ) {
            console.log(`ProcessorApply# Error at Terraform PLAN for provision (${idProv}) `);
            return Promise.reject({"success": false, "error": "Error at Terraform Plan", provStatus: "error_plan"}); 
        } else {
            const dateNow = new Date();
            let patch = {
                "status": "provisioning", 
                "statusVms": (prov.vmImage && prov.vmImage.vm1)? "Running" : "N/A",
                "runningFrom": dateNow, 
                "runningTime": 0, 
                "countExtend": 0
            };
            if ( prov.schedule && !prov.schedule.is24x7 ) {
                patch["startDateOnSchedule"] = dateNow;
                patch["endDateOnSchedule"] = dateNow;
            }
            return await db.provision.update(prov._id, patch);
        }
    } ).then( function(prov) {
        // TERRAFORM APPLY
        return tf.apply(prov);
    } ).then( async function(res) {
        if ( res.statusCode === 1 ) {
            console.log(`ProcessorApply# Error at Terraform APPLY for provision (${idProv})`);
        } else if ( res.statusCode === 137 ){
            console.log(`ProcessorApply# Apply container must have been killed!`);
            return Promise.reject({"success": false, "error": "Apply container must have been killed", provStatus: "aborted"}); 
        }
        var status = ( res.output.indexOf("Error:") !== -1 )? "error" : "provisioned";
        return await db.provision.update(prov._id, {"status": status});
    } ).then( async function(prov) {
        return tf.outputs(prov).then( async function(outputs){
            if ( outputs.barracudaAzureFqdn ) {
                let fqdn = outputs.barracudaAzureFqdn;
                delete outputs['barracudaAzureFqdn'];
                return await db.provision.update(prov._id, {"barracudaAzureFqdn": fqdn, "outputs": outputs});          
            } else {
                return await db.provision.update(prov._id, {"outputs": outputs});
            }           
        });

    } ).then( async function(prov) {
        if ( prov.isExternalAccess && prov.barracudaAzureFqdn ) {
            console.log(`ProcessorApply# Calling Barracuda service to create App and DNS CName for provision (${prov._id})`);
            barracuda.createApp(prov);
        }  
        return prov;
    } ).then( async function(prov) {
        // Application Gateway assign policy
        return azure.appgateway(prov, job.data._scenario);
    } ).then( async function(prov) {
        // Create Image
        return azure.createimage(prov, job.data._scenario);
    } ).then( function(prov) {
        if (prov.status === "provisioned") {
            sendEmail.sendProvisionSuccess(prov, job.data._scenario);
        } else {
            sendEmail.sendProvisionError(prov, job.data._scenario);
        }
        db.event.add({ user: prov.user._id, provision: prov._id, type: 'provision.finished' });
        return Promise.resolve({"success": true, provMongo: prov});
    } ).catch( function(err) {
        console.log("ProcessorApply# Provision: error", err);
        
        var errormsg = err.provStatus? err.provStatus : 'error'
        db.provision.update(prov._id, {"status": errormsg});
        db.event.add({ user: prov.user._id, provision: prov._id, type: 'provision.'+errormsg });

        if ( errormsg !== "aborted") {
            sendEmail.sendProvisionError(prov, job.data._scenario);
        }
        return Promise.reject({"success": false, "error": err});
    } );
}