var cookieParser = require('cookie-parser');
var csrf = require('./csrf');
var logger = require('../../logger');
var express = require('express');
var multipart = require('connect-multiparty');
var multipartMiddleware = multipart();
const FileType = require('file-type');
const passport = require('passport');
const xml2js = require('xml2js');
const uuid = require('uuid');
const { Strategy: SamlStrategy, SamlConfig } = require('passport-saml');
const { fileValidation } = require('../../api/constants/constants.js');
const {AuthProvider} = require('src_typescript_appice-core/dist/auth/index.js')
const { getRegex } = require('../../api/constants/constants.js')
var gifFrames = require('gif-frames');
moment = require('moment'),
    expose = require('express-expose'),
    mongo = require('mongoskin'),
    xss = require("xss"),
    atob = require('atob'),
    btoa = require('btoa'),
    formData = require("express-form-data"),
    crypto = require('crypto'),
    { body, check, validationResult } = require('express-validator');
let fs = require('fs');
let stream = require("stream");
let cors = require('cors'),
    mv = require('mv'),
    im = require('imagemagick'),
    cacheApi = require('../../api/utils/semusi.cache'),
    semusiMail = require('../../api/parts/mgmt/mail.js'),
    semusiMetrices = require('../../api/parts/mgmt/metrices.js'),
    ErrorMsg = require('../../api/constants/constants.js'),
    validateJSON = require('./public/scripts/validate.js')
Minio = require('minio'),
    semusiConfig = require('./config'),
    sys = require('sys');
let csvparse = require('csv'),
    arbit = require('arbit');
AWS = require('aws-sdk'),
    Azure = require('azure-storage');
multer = require('multer');
path = require('path');
var request = require('request');
dataProducer = require('../../api/utils/common.data.producer.js');
common = require('../../api/utils/common');
var csrfProtection = csrf({
    cookie: {
        //removing httpOnly for v1 as we need to access csrf from cookie to send in Ajax
        secure: true,       // Ensures the CSRF cookie is only sent over HTTPS
        sameSite: 'Lax'     // Controls whether the CSRF cookie is sent with cross-site requests
    }
});
const svgCaptcha = require('svg-captcha');
var app = express();
app.use(cookieParser())
const tenMinutesInSec = 600;
const upload = multer();
const authProv = new AuthProvider()
app.use(cors({
    origin: semusiConfig.accessContolAllowOrigin
}));
// Initialize Passport
app.use(passport.initialize());
app.use(passport.session());

var dbName;
var dbOptions = { safe: true };
// SAML authentication middleware
const authenticateSaml = passport.authenticate('saml', { session: false });

if (semusiConfig.IsProduction) {
    semusiDb = mongo.db(semusiConfig.mongodb.productionUrl, {
        native_parser: true, 'auto_reconnect': true, 'poolSize': 100, socketOptions: {
            keepAlive: true,
            connectTimeoutMS: 30000,
            socketTimeoutMS: 30000
        }
    });
}
else {
    semusiDb = mongo.db(semusiConfig.mongodb.localUrl, { native_parser: true });
}
semusiDb.ObjectID = mongo.ObjectID;

async function setupPassportSAMLStrategy() {
    try {

        const siteSettings = await retrieveSiteSettings();
        

        let samlConfig;

        // Check if samlConfig exists in siteSettings
        if (siteSettings.samlConfig && siteSettings.samlConfig.saml_entryPoint && siteSettings.samlConfig.saml_issuer && siteSettings.samlConfig.saml_callbackURL && siteSettings.samlConfig.saml_cert) {

            samlConfig = {
                entryPoint: siteSettings.samlConfig.saml_entryPoint,
                issuer: siteSettings.samlConfig.saml_issuer,
                callbackUrl: siteSettings.samlConfig.saml_callbackURL,
                cert: siteSettings.samlConfig.saml_cert,
            };
        } else {

            // Check if XML metadata file path exists in siteSettings
            if (siteSettings.xml_fileName) {

                const metadataFilePath = path.join(__dirname, '/public/appcertificates/common/', siteSettings.xml_fileName)
                const xmlData = fs.readFileSync(metadataFilePath, 'utf8');


                // Parse XML data
                const parser = new xml2js.Parser();
                const parsedXml = await parser.parseStringPromise(xmlData);


                // Extract SAML configuration from parsed XML
                const idpSSODescriptor = parsedXml["md:EntityDescriptor"]["md:IDPSSODescriptor"][0];
                const ssoService = idpSSODescriptor["md:SingleSignOnService"][0]["$"]["Location"];
                const entityID = parsedXml["md:EntityDescriptor"]["$"]["entityID"];
                const cert = idpSSODescriptor["md:KeyDescriptor"][0]["KeyInfo"][0]["X509Data"][0]["X509Certificate"][0].trim();

                samlConfig = {
                    entryPoint: ssoService,
                    issuer: entityID,
                    callbackUrl: siteSettings.samlConfig.saml_callbackUrl , // Replace with your actual callback URL
                    cert: cert
                };
            } else {
                logger.error('Missing both SAML configuration and XML metadata file path')
                throw new Error('Missing both SAML configuration and XML metadata file path');
            }

        }


        // Create the SAML strategy
        const samlStrategy = new SamlStrategy(samlConfig, async (profile, done) => {
            try {
                // Extract email from the SAML profile
                const email = profile.email;

                // Get the authentication provider instance
                const provider = authProv.createProvider("SSO")
                  
                const typeAuthProv =  await provider.getProvider(semusiConfig.cdnUrl)

                // Call the provision function to check if the email exists
                const response = await typeAuthProv.provision({ email: email });

                // If the user does not exist in the system, sign them up
                if (!response.exist) {
                    const full_name = profile.firstName; // Assuming firstName is available in profile
                    const password = ''; // You may want to generate or prompt for a password

                    // Signup the user with the authentication provider
                    const signresponse = await typeAuthProv.signup({ email, password, full_name });

                    // Handle successful signup if needed
                }

                // Return the SAML profile to the done callback
                return done(null, profile);
            } catch (error) {
                logger.error(`ERROR IN SAML STRATEGY ${JSON.stringify(error)}`)
                // Handle any errors that occur during the process
                return done(error);
            }
        });

        // Use the strategy with Passport
        passport.use(samlStrategy);
    } catch (err) {

        logger.error(`Failed to setup SAML strategy: ${JSON.stringify(err)}`);
    }
}

// Set up SAML strategy on application startup
setupPassportSAMLStrategy() .then(() => {
    logger.info('SAML strategy successfully set up');
    // Any additional code you want to run after setup
  }).catch(err => logger.error(`Error setting up SAML strategy:', ${err}`));

function shaFunction(str, addSalt) {
    var salt = (addSalt) ? new Date().getTime() : "";
    return crypto.createHmac(semusiConfig.shaV1Hash, salt + "").update(str + "").digest('hex');
}

function mdAlgo(str) {
    return crypto.createHash(semusiConfig.mdALgo).update(str + "").digest('hex');
}

function isGlobalAdmin(req) {
    return (req.session.gadm);
}

/** 
 *  This function updates the certificate information to the database and cache.
 *  it will work for both IOS and Android Case,, along with their dev and prod modes
 * @param {string} isModeDev - Indicates whether the mode is development or not.
 * @param {string} appId - The ID of the application.
 * @param {string} certName - The name of the certificate.
 * @param {string} fileData - The certificate file data.
 * @param {string} platform - The platform (ios/android) for which the certificate is being updated.
 */
function updateCertificateToDb(isModeDev, appId, certName, fileData, platform) {

    // Construct cache key based on platform and mode
    const cacheKey = platform === 'ios' ? 
                    (isModeDev === 'true' ? `iosCertificate_dev_${appId}` : `iosCertificate_prod_${appId}`) :
                    (isModeDev === 'true' ? `androidCertificate_dev_${appId}` : `androidCertificate_prod_${appId}`);

    // Determine the certificate field based on platform and mode
    const certField = platform === 'ios' ? 
                      (isModeDev === 'true' ? 'dev_ios_cert3' : 'ios_cert3') :
                      (isModeDev === 'true' ? 'dev_android_cert3' : 'android_cert3');
    
    // adding an additonal field to updateObj for ios only 
    const pushNotificationField = platform === 'ios' ? 
                                  (isModeDev === 'true' ? 'push_notification.apns.dev.dev_ios_cert3' : 'push_notification.apns.prod.ios_cert3') :
                                  null;


    // Prepare the default update object query
    const updateObj = {
        $set: { [certField]: certName, 'modifiedOn': moment.utc().valueOf() }
    };
    
    // If pushNotificationField exists, add it to the update object
    if (pushNotificationField) {
        updateObj.$set[pushNotificationField] = certName;
    }

    // For storing .json in Redis with a specific key 
    common.db.collection('apps').findOne({ '_id': semusiDb.ObjectID(appId) }, function(err, doc) {
        if (err) {
            logger.error(`Error in finding app: ${err}`);
            return;
        }

        const redisObj = {
            signingKey: certName,
            fcmKey: doc ? (doc.fcmKey_prod || doc.fcmKey_dev || "") : ""
        };

        if (certName && certName.endsWith('.json')) {
            const mode = isModeDev === "true" ? 'dev' : 'prod';
            const redisKey = `fcm_${appId}`;
            cacheApi.setKey(redisKey, JSON.stringify(redisObj));
        }
    });

    // Set the certificate data in the cache
    cacheApi.setKey(cacheKey, btoa(fileData));

    // Log the action
    logger.info(`${platform === 'ios' ? 'iOS' : 'Android'} Certificate saved at Cache for ${isModeDev === 'true' ? 'Dev' : 'Prod'} Mode`);


    // Perform the MongoDB update operation
    semusiDb.collection('apps').update({ '_id': semusiDb.ObjectID(appId) }, updateObj, function(err, app) {
        // Handle error if any
        if (err) {
            logger.error(`Error in updating certificates:, ${err}`);
        }else{
            logger.info(`Certificates Updated :`);
        }
    });
}


/** 
 *  This function updates the logo name  to the database.
 * @param {string} fileName - The filename of the logo uploaded.
 */
function updateSiteSettings(update) {

  // Define the query and update objects to update the 'siteS_settings' collection
  const query = { 'cdn': semusiConfig.cdnUrl };
  
  semusiDb.collection('site_settings').updateOne(query, update, { upsert: true }, (err, data) => {
      if (err || !data) {
          // If there is an error or the update fails,
          logger.error(`Error While Updating Logo Name to the setting ${JSON.stringify(err)}`);
        }else{
            logger.error(` Logo Name Updated to the setting`);
         }
  });
  
}

/**
 * Uploads a file from a temporary path to a specified target path .
 * @param {string} tmp_path - Temporary path of the uploaded file.
 * @param {string} realFilename - Name of the file to be saved.
 */
function uploadFileToDestination(tmp_path, targetPath) {

        // Define the target path where the file will be saved

        // Ensure the directory exists before copying the file
    fs.mkdir(path.dirname(targetPath), { recursive: true }, (err) => {
        if (err) {
            logger.error("Error creating directory:", err);
            return;
        }

                // Copy the file from temporary path to target path
        fs.copyFile(tmp_path, targetPath, (err) => {
            if (err) {
                logger.error("Error copying file:", err);
                return;
            }

            logger.info("File Uploaded successfully on the path");
        });
    });
}

/**
 * Checks if the logo image exists at the CDN path.
 * If not, downloads it from a provided URL and saves it locally.
 * @param {Object} sitesettings - Site settings object containing logo information.
 * @returns {Promise<boolean>} Promise that resolves to true if logo exists or was successfully downloaded; false otherwise.
 */
function ensureLogoAvailability(sitesettings) {
    return new Promise((resolve, reject) => {

             // Check if  logo information is present
        if (!sitesettings || !sitesettings.logo_name || !sitesettings.logo_url) {
            resolve(false); // Resolve with false if site settings or logo information is missing
            return;
        }

        const filename = sitesettings.logo_name;
        const targetPath = path.join(__dirname, '/public/assets/img/');
        const filePath = path.join(targetPath, filename);

                // Check if the logo file exists locally
        fs.access(filePath, fs.constants.F_OK, (err) => {
            if (err) {

                 // Logo file does not exist, download it from the specified URL
                const localFilePath = path.join(__dirname, '/public/assets/img/', filename);
                common.downloadFileFromMinio(sitesettings.logo_url, localFilePath)
                    .then(success => {
                        logger.info('File downloaded successfully:');
                        resolve(success); // Resolve with true upon successful download
                    })
                    .catch(error => {
                        logger.error(`Error downloading file: ${JSON.stringify(error)}` );
                        resolve(false); // Resolve with false if download fails
                    });
            } else {
                logger.info("Logo File exist in the path")
                resolve(true); // Resolve with true if file exists
            }
        });
    });
}
function validateUploadFile(str) {
    if (str.indexOf('.') !== str.lastIndexOf('.')) {
        return false;
    }
    return true;
}

function getFileExtension(file) {
    let pathParts = file.split(".")
    let fileExtension = pathParts[pathParts.length - 1];
    return fileExtension;
}



var router = express.Router();

// Manage Routing from Config (via ServerHost URL )
Object.keys(semusiConfig.redirectConfig).forEach((path) => {
    router.get(path, (req, res, next) => {
        res.redirect(semusiConfig.redirectConfig[path]);
    });
});

router.post('/sendMessage', function (req, res, next) {
    if (req.body.name && req.body.email && req.body.msg) {
        var message = {
            to: (semusiConfig.IsProduction) ? semusiConfig.productionSupportMail : semusiConfig.developmentSupportMail,
            subject: 'Contact',
            html: 'Hi,<br/><br/>' +
                'name : ' + req.body.name + '<br/>' +
                'email : ' + req.body.email + '<br/>' +
                'message : ' + req.body.msg + '<br/><br/>' +
                'New contact request by ' + req.body.name + '.<br/><br/>' +
                'Appice Team,<br/>' +
                'Server: <a href="' + semusiConfig.cdnUrl + '" target="_blank">' + semusiConfig.cdnUrl + '</a>'
        };

        semusiMail.sendMail(message);
        res.json({ msg: 'success', error: 0 });
    }
    else {
        res.json({ msg: "Please fill and select all fields", error: 1 });
    }
});

router.post('/subscribeNotificaton', function (req, res, next) {
    if (req.body.email) {
        var emailParts = req.body.email.split('@');
        var domainInitial = emailParts[1].split('.')[0];
        var domainindex = semusiConfig.Domains.indexOf(domainInitial);
        if (domainindex == -1) {
            semusiDb.collection('subscriptions').findOne({ "email": req.body.email }, function (err, member) {
                if (member) {
                    res.json({ msg: "You have already subscribe appice newsletters", error: 0 });
                }
                else if (!member) {
                    var subsObj = { email: req.body.email, createdAt: (moment().valueOf() / 1000) }
                    semusiDb.collection('subscriptions').insert(subsObj, function (error, result) {
                        if (error) {
                            res.json({ msg: 'subscriptions is failed', error: 1 });
                        } else if (result) {
                            if (req.body.blog) {
                                var message = {
                                    to: (semusiConfig.IsProduction) ? semusiConfig.productionSupportMail : semusiConfig.developmentSupportMail,
                                    subject: 'Subscribe Newsletters',
                                    html: 'Hi,<br/><br/>' +
                                        'Thank you for subscribing to appICE blog.<br/><br/>' +
                                        'Appice Team,<br/>' +
                                        'Server: <a href="' + semusiConfig.cdnUrl + '" target="_blank">panel.appice.io</a>'
                                };

                                semusiMail.sendMail(message);
                                res.json({ msg: 'Thank you for subscribing to our blog. We will get in touch soon.', error: 0 });
                            }
                            else {
                                var message = {
                                    to: (semusiConfig.IsProduction) ? semusiConfig.productionSupportMail : semusiConfig.developmentSupportMail,
                                    subject: 'Subscribe Newsletters',
                                    html: 'Hi there,<br/><br/>' +
                                        'Thank you for subscribing to the appICE newsletter. We will keep you posted with the latest news on AI powered marketing automation. <br/><br/>' +
                                        'Regards,<br/>' +
                                        'appICE Team'
                                };

                                semusiMail.sendMail(message);
                                res.json({ msg: 'Thanks for subscribe appice newsletters.', error: 0 });
                            }
                        }
                    });
                }
            });
        }
        else {
            res.json({ msg: omainInitial + " is not allowed domain", error: 1 });
        }
    }
    else {
        res.json({ msg: "Please enter your email address", error: 1 });
    }
});

router.post('/sendDemoRequest', function (req, res, next) {
    if (req.body.name && req.body.email && req.body.phone && req.body.company && req.body.app_status && req.body.app_download) {
        var emailParts = req.body.email.split('@');
        var domainInitial = emailParts[1].split('.')[0];
        var domainindex = semusiConfig.Domains.indexOf(domainInitial);
        logger.info("domain : " + domainInitial);
        if (domainindex == -1) {
            var message = {
                to: (semusiConfig.IsProduction) ? semusiConfig.productionSupportMail : semusiConfig.developmentSupportMail,
                subject: 'Request for demo',
                html: 'Hi,<br/><br/>' +
                    'name : ' + req.body.name + '<br/>' +
                    'email : ' + req.body.email + '<br/>' +
                    'phone : ' + req.body.phone + '<br/>' +
                    'company : ' + req.body.company + '<br/>' +
                    'Got an app : ' + req.body.app_status + '<br/>' +
                    'App download : ' + req.body.app_download + '<br/><br/>' +
                    'New demo request by ' + req.body.name + '<br/><br/>' +
                    'Appice Team,<br/>' +
                    'Server: <a href="' + semusiConfig.cdnUrl + '" target="_blank">' + semusiConfig.cdnUrl + '</a>'
            };

            semusiMail.sendMail(message);
            res.json({ msg: 'success', error: 0 });
        }
        else {
            res.json({ msg: omainInitial + " is not allowed domain", error: 1 });
        }
    }
    else {
        res.json({ msg: "Please fill and select all fields", error: 1 });
    }
});
function handlePostAuthLogin(req,res,response){
    switch (true) {
        case response.twofaAuth && response.alreadysent:
          // Render authentication page with specific parameters
          renderAuthenticationPage(req, res, '', '', false, false, true, false, false) 

          break;
      
        case response.reset:
          // Redirect to reset page with prid parameter
          res.redirect("/reset?prid=" + response.prid);
          break;
      
        case response.twofaAuth:
          // Send authentication information via email and redirect to authentication page
          semusiMail.sendAuthInfo(response.member.email, response.OTP);
          regenerateSessionAndRedirect(req, res, response,"/authentication" ,false);
          break;
      
        case response.allowMember:
          // Regenerate session and redirect to dashboard
          regenerateSessionAndRedirect(req, res, response, "/dashboard",true);
          break;
      
        default:
          // Render login page with specific parameters
          renderLoginPage(req,res,response.message)
      }

    // Function to regenerate session and handle redirection
    function regenerateSessionAndRedirect(req, res, response, redirectTo,userAuth) {
        req.session.regenerate(function (err) {
            if (err) {
                return res.json(400, {
                    error: 1,
                    msg: ErrorMsg.getErrorMessage("RetryError"),
                });
            }
            if (userAuth) {
                req.session.user_auth = true;
              
                // Generate sessionId
                const sessionId = uuid.v4(); // Generate a version 4 (random) UUID
                req.session.sessionId = sessionId;
                
                // Set session ID in session cookie or wherever it's needed
                saveMemberInCache(response.member.email, sessionId);
                }
            req.session.uid = response.member._id.toString();;
            req.session.login_time = Math.round(new Date().getTime() / 1000);
            res.redirect(redirectTo);
        });
    }
}

router.get('/signup', csrfProtection, async function (req, res, next) {
   renderSignupPage(req, res, '', '')
});

function handleOtheMembersAtCache(email) {

    cacheApi.getKey(email + "_", function (err, result) {
        if (err || result == null) {
            cacheApi.deleteKey(email, function (error, response) {
                if (err) {
                    logger.error(`Error While Deleting the user`)
                }
            })
        } else {
            cacheApi.setKey(email, result);
            cacheApi.expire(email, tenMinutesInSec);
            handleOtheMembersAtCache(email + '_')
        }
    })
}
// This Function saves the email of the user in redis with its value as IP_SessionId
function saveMemberInCache(email,sid) {
    cacheApi.getKey(email, function (err, result) {
        if (err) {
            logger.error(`Error while Saving memeber at Cache${err}`);
        } else if (result == null) {
            //if there is no user with this email  set =>
            cacheApi.setKey(email, sid);
            cacheApi.expire(email, tenMinutesInSec);
        } else {
            var nemail = email + "_";
            saveMemberInCache(nemail, sid);
        }
    });
}

/**
 * This function reverses the encryption process by shifting each character's Unicode code point 
 * backwards by a fixed number of positions.
 * 
 * @param {string} str The encrypted str to be decrypted.
 * @returns {string} The decrypted str.
 */

function processString(str) {
    let deCodedStr = '';
    for (let i = 0; i < str.length; i++) {
        // Reverse the shift by a fixed number of positions
        let charCode = str.charCodeAt(i);
        deCodedStr += String.fromCharCode(charCode - 2); 
    }
    return deCodedStr;
}

/**
 * Validates the file name, file path, and file extensions.
 * @param {string} app_cert_name The name of the uploaded certificate file.
 * @param {string} path The path of the uploaded file.
 * @param {string} name The name of the uploaded file.
 * @param {string} platform The platform for which the file is uploaded (ios or android).
 * @returns {boolean} True if the file name, path, and extensions are valid; otherwise, false.
 */
function validateFileAndExtension(app_cert_name, path, name, platform) {
    // Check if each file and filename is valid
    const isValidFile = validateUploadFile(app_cert_name) && validateUploadFile(path) && validateUploadFile(name);

    // Get the possible file extensions as per platform 
    // For iOS (.p8 and .p12) and for Android (.json) in array 
    const fileExtensions = platform === "ios" ? fileValidation('iosCert') : fileValidation('androidCert');

    // Check if the file extensions are valid
    const isFileExtensionValid = fileExtensions.includes(getFileExtension(path)) && fileExtensions.includes(getFileExtension(app_cert_name));

    return isValidFile && isFileExtensionValid;
}
function saveLoginTime(email) {
    const emailQuery =  { 'email': { $regex: new RegExp('^' + email, 'i') } };

    semusiDb.collection('members').findOne(emailQuery, function (err, member) {
        if (err) {

        } else {

            var previous_login_time = ""
            if (member.current_login_time) {

                previous_login_time = member.current_login_time
            }

            semusiDb.collection('members').update(emailQuery, { '$set': { "current_login_time": common.getdatetimeFromEpoch(Date.now()), "previous_login_time": previous_login_time } }, function (err, member) {
                if (err) {
                    logger.error(`Error while Saving Login time`)
                } else {
                    logger.info(`Login Time of User Saved `)
                }
            });

        }
    })

}
router.get('/logout', function (req, res, next) {
    const requestAgentinfo = req.headers[`${'user-agent'}`];
    const datetime = new Date()
    logger.info(`User Logged Out at===> ${datetime}`);
    // get the sessionId from request
    const sid =  req.session.sessionId;
    if (req.session) {
        logger.info(`User ID logout  ===>${req.session.uid}`)
        semusiDb.collection('members').findOne({ "_id": semusiDb.ObjectID(req.session.uid) }, function (err, member) {
            if (member) {
                removeUseratCache(member.email)
                // remove User's data from Redis 
                function removeUseratCache(email) {
                    cacheApi.getKey(email, function (err, result) {
                        if (err || result == null) {
                            logger.error(`Error While retriiving user from cache${err}`);
                            req.session.uid = null;
                            req.session.login_time = null;
                            req.session.user_auth = null;
                            req.session.sessionId = null;

                            res.clearCookie('uid');
                            res.clearCookie('user_auth');
                            res.clearCookie('login_time');
                            res.redirect('/login')
                        } else {


                            if (result == sid) {
                                cacheApi.deleteKey(email, function (error, response) {
                                    if (error) {
                                        logger.error(`Error in removing the user`)
                                    } else {
                                        req.session.uid = null;
                                        req.session.gadm = null;
                                        req.session.sessionId = null;
                                        req.session.login_time = null;
                                        req.session.user_auth = null;
                                        res.clearCookie('uid');
                                        res.clearCookie('gadm');
                                        res.clearCookie('appICE');
                                        res.clearCookie('login_time');
                                        res.clearCookie('user_auth');
                                        req.session.destroy(function () {
                                        });

                                        res.expose(semusiConfig.serverName, "serverName");
                                        handleOtheMembersAtCache(email)
                                        logger.info("User Logged Out Sucessfulyy")
                                        res.redirect('/login');


                                    }
                                });
                            } else {
                                removeUseratCache(email + "_")
                            }
                        }
                    });
                }
            }
        });
    }

});


router.get('/dashboard', function (req, res, next) {
    let concurrentLoginCheck = 0;
    if (!req.session.uid || !req.session.login_time) {
        res.redirect(xss('/login'));
    }
    else {
        if (!req.session.user_auth) {
            semusiDb.collection('members').findOne({ "_id": semusiDb.ObjectID(req.session.uid) }, function (err, member) {
                const email = member.email;
                startTwoFactorAuth(email, req, res);
            })
        } else {
            semusiDb.collection('members').findOne({ "_id": semusiDb.ObjectID(req.session.uid) }, function (err, member) {
                if (err) {
                    logger.error("error => " + err);
                } else if (member) {
                    const sid = req.session.sessionId;
                    logger.info("member => " + member);
                    var adminOfApps = [],
                        userOfApps = [],
                        semusiGlobalApps = {},
                        semusiGlobalAdminApps = {};
                    displayPref = member.displayPref;
                   var user_role = member.user_role;
                    member.user_id = crypto.createHash(semusiConfig.mdALgo).update(member._id + member.email).digest('hex');
                    member.user_hash = crypto.createHash(semusiConfig.shaV1Hash).update('xuiee4eb' + member.user_id).digest('hex');

                    initiateRenderDashboard(member.email, res);


                    function initiateRenderDashboard(email, res) {
                        // check at Redis If the User is  Not Present  Logout the user
                        cacheApi.getKey(email, function (err, result) {
                            if (err) {
                                logger.error(`Error in finding user from redis / dasboard  ${err}`);

                            } else if (result == null) {
                                //no result found
                                res.redirect('/logout');
                            } else {
                                var allAppdata = []

                                if (member["global_admin"]) {
                                    // if user is global admin
                                    semusiDb.collection("apps").find({ isAppDeleted: { $ne: "true" } }).sort({ createdOn: -1 }).toArray(function (err, apps) {
                                        checkForapps(apps); //Call To Function For Apps TO check for Email auth
                                        allAppdata = apps 
                                    });
                                } else {
                                    var availableAppids = [];
                                    var roles = Object.keys(member.user_role);

                                    roles.forEach(function (role) {
                                      var roleAppids = member.user_role[role];
                                      roleAppids.forEach(function (appid) {
                                        availableAppids.push(semusiDb.ObjectID(appid));
                                      });
                                    });

                                    if (availableAppids.length == 0) {
                                      checkForapps([]);
                                    } else {
                                      semusiDb.collection("apps").find({_id: { $in: availableAppids },isAppDeleted: { $ne: "true" },}).sort({ createdOn: -1 }).toArray(function (err, apps) {
                                          checkForapps(apps); //Call To Function For Apps To Check for Email auth
                                          allAppdata = apps;
                                        });
                                    }
                                }

                                function checkForapps(apps) {
                                    for (var i = 0; i < apps.length; i++) {
                                        if (apps[i]["concurrentLogin"] != undefined && apps[i]["concurrentLogin"] == "OFF") {
                                            concurrentLoginCheck = concurrentLoginCheck + 1;
                                        }
                                    }


                                if (concurrentLoginCheck > 0) {

                                    // concurrent login is OFF
                                    //check if this user is already logged in
                                    if (result == sid) {
                                        allowRenderingDashboard();
                                    } else {
                                        // someone is logged in already and concurrent login is off so make him logout
                                        res.redirect("/logout");
                                    }
                                } else {

                                    // concurrent login is on
                                    //check if this user is already logged in
                                    if (result == sid) {
                                        allowRenderingDashboard();
                                    } else {
                                        initiateRenderDashboard(email + "_", res);
                                    }
                                }
                               }
                            }
                            function allowRenderingDashboard() {
                                message = '';
                                var currentappid = {};
                                var currentappvars = {};
                                //this variables holds true if the system has started receiving any data
                                var isdatacoming = false;
                                var action = false;


                                if (req.query.action) {
                                    action = req.query.action;
                                }
                                else {
                                    action = false;
                                }

                                if (req.query.app_id) {
                                    currentappid = req.query.app_id;
                                    var matchappid = false;

                                    //check if the query app id exists in the list of our userapps
                                    for (var i = 0; i < userOfApps.length; i++) {
                                        if (currentappid == userOfApps[i]._id) {
                                            matchappid = true;
                                            break;
                                        }
                                    }

                                    if (currentappid != '') {
                                        //check for sessions
                                        semusiDb.collection('app_users' + currentappid).count({}, function (err, deviceInfo) {
                                            if (deviceInfo) {
                                                isdatacoming = true;
                                            }
                                        });

                                        semusiDb.collection('apps').findOne({ _id: semusiDb.ObjectID(currentappid) }, function (err, currData) {
                                            if (err) {
                                                logger.error(err)
                                            } else {
                                                let allowedList = '';           // set the default src for all apps 
                                                if(currData.allowedItems && currData.allowedItems.length > 0){
                                                     //if list is found Push them 
                                                    currData.allowedItems.forEach(function(url) {
                                                        allowedList += ' ' + url;
                                                    });
                                                    
                                                }
                                                //Update csp policy 
                                                semusiConfig.appListSrc = allowedList
                                                if (currData != '') {
                                                    currentappvars.currentAppName = currData.name;
                                                    currentappvars.currentAppIcon = currData.icon
                                                }
                                            }
                                        });
                                    }
                                }

                                // Turned a dead code into Working 
                                // This query will get the SiteSetting from the db and pass the auth type to the frontend in the render fucntion
                                semusiDb.collection('site_settings').findOne({"cdn": semusiConfig.cdnUrl}, function (err, siteSettings) {
                                    // by default the auth is disabled 
                                    let sso_type = 'disabled'
                                    // if setting is found ... 
                                    if(siteSettings) {
                                        // If sso_type is present in the db 
                                        sso_type = siteSettings.sso_type || 'disabled';
                                  }
                                    req.session.uid = member["_id"];
                                    req.session.gadm = (member["global_admin"] == true);
                                    res.header('Cache-Control', 'no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0');

                                    delete member["password"];


                                    res.render('dashboard', {
                                        "message": message,
                                        userOfApps: allAppdata,
                                        semusiVersion: "13.10",
                                        member: member,
                                        newPanelUrl:semusiConfig.newPanelUrl,
                                        displayPref: displayPref,
                                        sessionId : sid,
                                        currentappid: currentappid,
                                        currentAppName: currentappvars.currentAppName,
                                        currentAppIcon: currentappvars.currentAppIcon,
                                        adminAppids:user_role.admin  ?  JSON.stringify(user_role.admin)  : [],
                                        managerAppids:user_role.manager  ? JSON.stringify(user_role.manager)  : [],
                                        marketerAppids:user_role.marketer  ?  JSON.stringify(user_role.marketer)  : [],
                                        isdatacoming: isdatacoming,
                                        serverName: semusiConfig.serverName,
                                        cdnUrl: semusiConfig.cdnUrl,
                                        action: action,
                                        sso_type:sso_type,          // passing to the frontend 
                                        GoogleMapApiKey: semusiConfig.googleMapApiKey,
                                        cMonth: moment.utc().format('MMM YYYY'),
                                        t: semusiConfig.shaV1Hash
                                    });
                                });
                            }
                        });
                    }
                } else {
                    if (req.session) {
                        req.session.uid = null;
                        req.session.gadm = null;
                        req.session.login_time = null;
                        res.clearCookie('uid');
                        res.clearCookie('gadm');
                        res.clearCookie('login_time');
                        req.session.destroy(function () {
                        });
                    }
                    res.expose(semusiConfig.serverName, serverName);
                    res.redirect('/login');
                }
            });

        }
    }
});


/**
 * Retrieves common parameters used for rendering pages.
 * @param {} req - The request object.
 * @returns {Promise<Object>} An object containing common parameters.
 */
async function renderCommonParams(req) {
    // Retrieve site settings asynchronously
    const siteSettings = await retrieveSiteSettings();

    // Check logo processing status asynchronously
    const isLogoProcessed = await ensureLogoAvailability(siteSettings);

    // Initialize authentication type to 'disabled' by default
    let authType = 'disabled';

    // Determine authentication type based on site settings
    if (siteSettings && siteSettings.sso_type) {
        authType = siteSettings.sso_type;
    }

    // Return an object containing common parameters used in rendering
    return {
        siteSettings,
        isLogoProcessed,
        authType,
        csrfToken: req.csrfToken(), // Generate CSRF token for security
        t: semusiConfig.shaV1Hash,
        is_sso : siteSettings ? siteSettings.is_sso : null,
        logo_name: siteSettings ? siteSettings.logo_name : null, // Logo name from site settings
        portal_name: siteSettings ? siteSettings.portal_name : null,  // Portal name from site settings
        serverName: semusiConfig.serverName,
        cdnUrl: semusiConfig.cdnUrl
    };
}

/**
* Renders the signup page with specific parameters.
* @param {*} req - The request object.
* @param {*} res - The response object.
* @param {string} alert - Alert message for the signup page.
* @param {string} message - Message to display on the signup page.
*/
async function renderSignupPage(req, res, alert, message) {

    // Retrieve common parameters for rendering
    const params = await renderCommonParams(req);

    // Fetch site settings to check if CAPTCHA is enabled
    semusiDb.collection('site_settings').findOne({"cdn": semusiConfig.cdnUrl}, async (err, siteSettings) => {
        if (err) {
            return res.status(500).send("Internal Server Error");
        }

        const captchaEnabled = siteSettings?.captcha === 'enable';

        let base64CaptchaSvg = '';
        if (captchaEnabled) {
            // Create CAPTCHA
            const captcha = svgCaptcha.create({
                background: '#ffffff',
                color: true,
                noise: 2,
                width: 200,
                height: 40
            });
            req.session.captcha = captcha.text; // Save CAPTCHA text in session
            base64CaptchaSvg = Buffer.from(captcha.data).toString('base64'); // Convert CAPTCHA SVG to Base64
        }

        // Render the 'signup' page with CAPTCHA SVG included if CAPTCHA is enabled
        res.render('signup', {
            alert,
            message,
            captchaSvg: base64CaptchaSvg,
            captchaEnabled, // Pass captchaEnabled flag to the template
            ...params,
            homePageNav: semusiConfig.homePageNav
        });
    });
}

/**
* Renders the authentication page with specific parameters.
* @param {*} req - The request object.
* @param {*} res - The response object.
* @param {string} alert - Alert message for the authentication page.
* @param {string} message - Message to display on the authentication page.
* @param {boolean} isAuth - Authentication status.
* @param {boolean} otpSent - Whether OTP is sent.
* @param {boolean} alreadySent - Whether OTP has already been sent.
* @param {boolean} isExpired - Whether the authentication session has expired.
* @param {boolean} isBlock - Whether the user is blocked.
*/

async function renderAuthenticationPage(req, res, alert, message, isAuth, otpSent, alreadySent, isExpired, isBlock) {

    // Retrieve common parameters for rendering
    const params = await renderCommonParams(req);

    // Render the 'authentication' page with specific parameters
    res.render('authentication', { alert, message, auth: isAuth, otpsent: otpSent, alreadysent: alreadySent, expired: isExpired, blocked: isBlock, ...params });
}


/**
* Renders the forgot password page with specific parameters.
* @param {*} req - The request object.
* @param {*} res - The response object.
* @param {string} alert - Alert message for the forgot password page.
* @param {string} message - Message to display on the forgot password page.
*/
async function renderForgotPage(req, res, alert, message) {
    // Retrieve common parameters for rendering
    const params = await renderCommonParams(req);
    
    // Fetch site settings to check if CAPTCHA is enabled
    semusiDb.collection('site_settings').findOne({"cdn": semusiConfig.cdnUrl}, async (err, siteSettings) => {

    const captchaEnabled = siteSettings?.captcha === 'enable';
    let captchaSvg = null;
    if (captchaEnabled) {
        // Create CAPTCHA
        const captcha = svgCaptcha.create({
            background: '#ffffff',
            color: true,
            noise: 2,
            width: 200,
            height: 40
        });
        req.session.captcha = captcha.text; // Save CAPTCHA text in session
        captchaSvg = Buffer.from(captcha.data).toString('base64'); // Convert CAPTCHA SVG to Base64
    }

    // Render the 'forgot' page with CAPTCHA if enabled
    res.render('forgot', {
        alert: alert,
        message: message,
        captchaSvg: captchaSvg,
        captchaEnabled: captchaEnabled,
        csrf: req.session._csrf,
        ...params
    });
});
}


/**
* Renders the reset password page with specific parameters.
* @param {*} req - The request object.
* @param {*} res - The response object.
* @param {string} alert - Alert message for the reset password page.
* @param {string} prid - Password reset ID.
*/
async function renderResetPage(req, res, alert, prid) {

        // Retrieve common parameters for rendering    
    const params = await renderCommonParams(req);

        // Render the 'reset' page with specific parameters
    res.render('reset', { alert, prid, ...params });
}

/**
 * Render the login page with optional message and alert.
 *
 * @param {Object} req - Express request object
 * @param {Object} res - Express response object
 * @param {string} [message=''] - Optional message to display on the login page
 * @param {string} [alert=''] - Optional alert message to display on the login page
 */
function renderLoginPage(req, res, message = '', alert = '') {
    semusiDb.collection('site_settings').findOne({"cdn": semusiConfig.cdnUrl}, async (err, siteSettings) => {
        if (err || !siteSettings) {
            // Render the login page with default configurations
            res.render('login', {
                alert: alert,
                message: message,
                captchaSvg: null, // No CAPTCHA
                "csrf": req.session._csrf,
                csrfToken: req.csrfToken(),
                "serverName": semusiConfig.serverName,
                "forgetPassType": semusiConfig.passForEmail,
                "homePageNav": semusiConfig.homePageNav,
                t: semusiConfig.shaV1Hash,
                "cdnUrl": semusiConfig.cdnUrl,
                adAuthType: 'disabled',
                logo_name: null,
                portal_name: null,
                is_sso: null,
                captchaEnabled: false // CAPTCHA is disabled
            });
        } else {
               // Determine whether CAPTCHA is enabled or disabled
            const captchaEnabled = siteSettings.captcha === 'enable';
              // Create CAPTCHA
              const captcha = svgCaptcha.create({
                  background: '#ffffff',
                  color: true,
                  noise: 2,
                  width: 200,
                  height: 40
              });

              req.session.captcha = captcha.text; // Save CAPTCHA text in session
              req.session.captchaEnabled = captchaEnabled; // Save CAPTCHA text in session
              
              // Convert CAPTCHA SVG to Base64
              const captchaSvg = captchaEnabled ? Buffer.from(captcha.data).toString('base64') : null;


            res.render('login', {
                alert: alert,
                message: message,
                captchaSvg: captchaSvg,
                "csrf": req.session._csrf,
                csrfToken: req.csrfToken(),
                "serverName": semusiConfig.serverName,
                "forgetPassType": semusiConfig.passForEmail,
                "homePageNav": semusiConfig.homePageNav,
                t: semusiConfig.shaV1Hash,
                "cdnUrl": semusiConfig.cdnUrl,
                adAuthType: siteSettings.sso_type,
                logo_name: siteSettings.logo_name,
                portal_name: siteSettings.portal_name,
                is_sso: siteSettings.is_sso || null,
                captchaEnabled: captchaEnabled
            });
        }
    });
}
router.get('/sso-dashboard', csrfProtection, async function (req, res, next) {

        authenticateSaml(req, res, next);    // Call authenticateSaml function directly

})

router.get('/login', csrfProtection, async function (req, res, next) {
    if (req.headers.host === 'appice.io') {
        res.redirect(semusiConfig.cdnUrl + "/login");
    }

    logger.info(JSON.stringify(req.session.uid))
    if (req.session.uid && req.session.login_time) {
        if (req.session.user_auth) {
            res.redirect('/dashboard');
        } else {
            const curr_timestamp = Math.round(new Date().getTime() / 1000);
            const TEN_MIN = 10 * 60;
            if ((curr_timestamp - req.session.login_time) < TEN_MIN) {
                semusiDb.collection('members').findOne({ "_id": semusiDb.ObjectID(req.session.uid) }, function (err, member) {
                    const email = member.email;
                    if (!err || member != null) {
                        startTwoFactorAuth(email, req, res);
                    }
                })
            } else {
                res.redirect('/logout');
            }
        }
    } else {
        logger.info(req.session.uid)
        semusiDb.collection('members').count({}, function (err, memberCount) {
            if (memberCount) {
                renderLoginPage(req,res )
            } else {
                res.expose(semusiConfig.serverName, "serverName");
                res.redirect('/signup');
            }
        });
    }
});

router.get('/forgot', csrfProtection, function (req, res, next) {
    if (req.session.uid && req.session.login_time) {
        res.expose(semusiConfig.serverName, "serverName");
        res.redirect('/dashboard');
    } else {
            renderForgotPage(req,res,'', '')
    }
});

router.get('/authentication', csrfProtection, (req, res) => {

    if (!req.session.uid || !req.session.login_time || req.session.user_auth) {
        res.redirect(xss('/login'));
    }else{
    //getting email
    semusiDb.collection('members').findOne({ "_id": semusiDb.ObjectID(req.session.uid) }, function (err, member) {
        if (!err || member) {

            renderAuthenticationPage(req,res,'','',false,true,false ,false,false)

        }

    })

  }
});

router.post("/downloadExportCsv", async (req, res) => {
    logger.info(`Export Csv Download Started  `);

    var minioClient = new Minio.Client({
        endPoint: semusiConfig.endPoint,
        useSSL: semusiConfig.useSSL,
        accessKey: semusiConfig.accessKey,
        secretKey: semusiConfig.secretKey,
    });

    semusiDb.collection("exportjobs_" + req.body.app_id).find({ _id: semusiDb.ObjectID(req.body.export_id) }).toArray(function (err, exportResult) {
        if (err && exportResult == []) {
            logger.error(`Error while getting Export Csv Details from db==${JSON.stringify(err)}`);
        } else {
            logger.info(`Export Details Found Now Streaming Data`);
            var exportDetails = exportResult[0];

            minioClient.getObject(
                semusiConfig.minioBuckets.exportsCsv,
                exportDetails.exportjobentityurl,
                function (err, dataStream) {
                    if (err) {
                        logger.error(`Error While Streaming Data in Minio ${JSON.stringify(err)}`);
                        res.redirect("/dashboard?action=insideapp#/jobs/export/" + req.body.export_id);
                    } else {
                        logger.info(` Streaming Data Successfully Now Downloading the Export Csv`);
                        res.attachment(exportDetails.exportjobentityurl);
                        dataStream.pipe(res);
                    }
                }
            );
        }
    });
});

router.post('/authentication', csrfProtection, [check('otp', 'otp must be numeric').isNumeric()], (req, res) => {
    let otp = xss(req.body.otp);
    const errors = validationResult(req);
    if (!errors.isEmpty()) {
        const alert = errors.array();
        renderAuthenticationPage(req,res,alert,'',      false, false, false ,false, false  )
    } else {
        OTP = otp;
        const curr_timestamp = Date.now();
        const FIVE_MIN = 5 * 60 * 1000;
        //getting email
        semusiDb.collection('members').findOne({ "_id": semusiDb.ObjectID(req.session.uid) }, function (err, member) {
            if (err) {
                logger.error("error => " + err);
            } else if (member) {
                const email = member.email;
                semusiDb.collection('otp_verification').findOne({ email: email }, function (err, verify) {

                    //OTP NOT FOUND
                    if (!verify) {
                        renderAuthenticationPage(req,res,'','No OTP Generated', false, false, false ,false, false  )

                    }
                    //Check for number of trials less than 5 times
                    if (!err || verify) {
                        if (verify.loggedIn_Count != 5) {

                            //OTP NOT MATCH
                            if (verify.otp != OTP) {

                                semusiDb.collection('otp_verification').update({ email: email }, { $inc: { loggedIn_Count: 1 } }, function (err, data) {
                                    if (!err || data) {
                                        renderAuthenticationPage(req,res,'','Invalid OTP', false, false, false ,false, false  )
                                    }
                                })
                            }

                            //OTP EXPIRED AFTER 5 MINT
                            else if ((curr_timestamp - verify.timestamp) > FIVE_MIN) {

                                semusiDb.collection('otp_verification').remove({ otp: OTP }, function (err, data) {
                                    if (!err || data) {
                                        req.flash('info', 'OTP Expired');
                                        renderAuthenticationPage(req,res,'','', false, false, false ,true, false  )
                                    }
                                });

                            }
                            else {
                                //SUCCESSFULLY AUTHENTICATED
                                semusiDb.collection('otp_verification').remove({ otp: OTP }, function (err, data) {
                                    if (!err || data) {
                                        req.session.user_auth = true;


                                        saveLoginTime(member.email)
                                         const sessionId = uuid.v4(); // Generate a version 4 (random) UUID
                                       // Set session ID in session cookie or wherever it's needed
                                        req.session.sessionId = sessionId;
                                        saveMemberInCache(member.email, sessionId);
                                        renderAuthenticationPage(req,res,'','', true, false, false ,false, false  )

                                    }
                                });
                            }
                        }
                        else {
                            //Blocking account
                            semusiDb.collection('members').update({ "_id": semusiDb.ObjectID(req.session.uid) }, { $set: { isblocked: true } }, function (err, data) {
                                if (!err || data) {
                                    semusiDb.collection('otp_verification').remove({ email: email }, function (err, data) {
                                        if (!err || data) {
                                            renderAuthenticationPage(req,res,'','', false, false, false ,false, true  )
                                        }
                                    });
                                }
                            })
                        }

                    }

                })
            }
        })
    }
});

router.get('/reset', csrfProtection, function (req, res, next) {
    res.expose(semusiConfig.serverName, "serverName");
    if (req.query.prid) {
        semusiDb.collection('password_reset').findOne({ prid: req.query.prid }, function (err, passwordReset) {
            var timestamp = Math.round(new Date().getTime() / 1000);
            if (passwordReset && !err) {
                if (timestamp > (passwordReset.timestamp + 57600)) {
                    req.flash('info', 'reset.invalid');
                    res.redirect('/forgot');
                } else {
                    renderResetPage(req,res,'', req.query.prid)
                }
            } else {
                req.flash('info', 'reset.invalid');
                res.redirect('/forgot');
            }
        });
    } else {
        req.flash('info', 'reset.invalid');
        res.redirect('/forgot');
    }
});


router.post('/apps/ioscertificate_S3_AWS', function (req, res) {
    if (!req.body.app_cert_id) {
        res.end();
        return true;
    }

    var target_path = '';

    //set the aws region
    AWS.config.region = semusiConfig.AWS_REGION;
    AWS.config.update({ accessKeyId: semusiConfig.AWSLAMBDA_ACCESS_KEY_ID, secretAccessKey: semusiConfig.AWSLAMBDA_SECRET_KEY });

    var bucketName;

    if (semusiConfig.IsProduction) {
        bucketName = semusiConfig.S3_PROD_CERTBUCKET;
    }
    else {
        bucketName = semusiConfig.S3_STAGING_CERTBUCKET;
    }

    var tmp_path = req.files.image.path,
        filename = req.files.image.name,
        type = req.files.image.type,
        app_id = req.body.appid;

    AWS.config.region = semusiConfig.AWS_REGION;
    AWS.config.update({ accessKeyId: semusiConfig.AWSLAMBDA_ACCESS_KEY_ID, secretAccessKey: semusiConfig.AWSLAMBDA_SECRET_KEY });

    var s3bucket = new AWS.S3();
    var bucket = semusiConfig.minioBuckets.campaignImages;
    filename = moment.utc() + '_' + filename;
    var keyVar = "uploads/campaignFiles/campaignimages/" + app_id + "/" + filename;

    s3bucket.createBucket({ Bucket: bucket }, function (err, data) {
        logger.info("bucket creation: " + err ? "FAIL" : "SUCCESS");
        var fileBuffer = fs.readFileSync(tmp_path);
        var params = { ACL: 'public-read', Bucket: bucket, keyVar: keyVar, Body: fileBuffer, ContentType: type };
        s3bucket.upload(params, function (err, response) {
            if (err) {
                res.send('');
            } else {
                res.send(response.Location);
            }
        });
    });

});

router.post('/apps/ioscertificate_S3', function (req, res) {
    if (!req.body.app_cert_id) {
        res.end();
        return true;
    }

    var bucketName, blobContainerCDN;

    if (semusiConfig.IsProduction) {
        bucketName = semusiConfig.S3_PROD_CERTBUCKET;
        blobContainerCDN = semusiConfig.blobContainerCDN + bucketName
    }
    else {
        bucketName = semusiConfig.S3_STAGING_CERTBUCKET;
        blobContainerCDN = semusiConfig.blobContainerCDN + bucketName
    }

    var tmp_path = req.files.image.path,
        filename = req.files.image.name,
        type = req.files.image.type,
        app_id = req.body.appid;

    const blobService = Azure.createBlobServiceWithSas(semusiConfig.azureApiBlobSASURL, semusiConfig.azureApiStorageSASToken);
    var bucket = semusiConfig.minioBuckets.campaignImages;
    filename = moment.utc() + '_' + filename;
    var keyVar = "uploads/campaignFiles/campaignimages/" + app_id + "/" + filename;

    blobService.createBlockBlobFromLocalFile(bucket,
        keyVar,
        tmp_path,
        (error, result) => {
            if (error) {
                // Handle blob error
                res.send('');
            } else {
                logger.info(`result => ${JSON.stringify(result)}`);
                logger.info('Upload is successful');
                res.send(blobContainerCDN + "/" + keyVar);
            }
        });
});

router.post('/apps/fcmcertificate', function (req, res) {
    // var fileBuffer = fs.readFileSync(req.files.fcm_cert.path);
    // fs.writeFile('uploads/', fileBuffer, function (err, result) {
    //     res.send('Uploaded');
    // });
    fs.readFile(req.files.fcm_cert.path, function (err, data) {
        var fcm_certName = req.body.name;

        if (!fcm_certName) {
            logger.info('There was an error');
            res.end();
        } else {
            var storagePath = semusiConfig.fcmCertificateLocation + fcm_certName;
            let updateFCM = {
                ['fcmCert_' + req.body.mode]: fcm_certName
            }

            fs.writeFile(storagePath, data, function (err) {
                semusiDb.collection('apps').update({ _id: semusiDb.ObjectID(req.body.fcm_cert_id) }, { $set: updateFCM }, function (err, currData) {
                    if (err) {
                        logger.error(err)
                    } else {
                        currData.fcmCert = fcm_certName;
                    }
                });
                res.send(fcm_certName);
            });
        }
    });
});

router.post('/apps/ioscertificate', csrfProtection, multipartMiddleware, async function (req, res) {
    if (!req.files.app_cert || !req.body.app_cert_id || !req.body.app_cert_name) {
        res.status(400).send("something went wrong ");
        return false;
    }

    try {

        // destructure req.body
        const { app_cert_name ,app_cert_id , platform } = req.body;
        // destructure req.files
        const { path, name } = req.files.app_cert;

        // validate file ,filename and its extension from a common function
        if (validateFileAndExtension(app_cert_name, path, name, platform)) {
            var tmp_path = req.files.app_cert.path,
                type = req.files.app_cert.type;
            let filename = req.files.app_cert.name;
            let app_id = req.body.app_cert_id;
            let rawFileName = req.files.app_cert.name;
            if (filename === undefined) {
                var ags = tmp_path.split("/");
                ags = ags[ags.length - 1];
                ags = ags.split(".");
                rawFileName = ags[0];
                type = ags[ags.length - 1];
            }
            // create file name 
            rawFileName = moment.utc() + '_' + rawFileName;
            filename = rawFileName + '.' + type;
            var base = semusiConfig.blobContainerCDN
            if (semusiConfig.uploadAssets[0] == "Azure") {
                base = semusiConfig.blobContainerCDN + app_id + "/"
            }
            var returnObj = { url: filename, baseURL: base }
            await uploadAssets(filename, tmp_path, app_id, type);
            returnObj.type = type;

            res.send(returnObj);
        } else {
            logger.error("Failed to upload Certs => Please Enter Only .p8 or .p12 Certificate Files")
            res.status(400).send("Invalid file format. Only .p8 or .p12 files are allowed.");
        }
    } catch (error) {
        logger.error(`error in ioscertificates ${error}`)
        res.status(400).send("something went wrong");
    }
});

// upload certification on s3 server
function uploadCertificateS3AWS(req, res, path, tmp_path, type) {

    var target_path = '';
    //set the aws region
    AWS.config.region = semusiConfig.AWS_REGION;
    AWS.config.update({ accessKeyId: semusiConfig.AWSLAMBDA_ACCESS_KEY_ID, secretAccessKey: semusiConfig.AWSLAMBDA_SECRET_KEY });

    var bucketName;

    if (semusiConfig.IsProduction) {
        bucketName = semusiConfig.S3_PROD_CERTBUCKET;
    }
    else {
        bucketName = semusiConfig.S3_STAGING_CERTBUCKET;
    }

    var bucket = bucketName;
    var keyVar = path;

    s3bucket.createBucket({ Bucket: bucket }, function (err, data) {
        var fileBuffer = fs.readFileSync(tmp_path);
        var params = { ACL: 'public-read', Bucket: bucket, keyVar: keyVar, Body: fileBuffer, ContentType: type };
        s3bucket.upload(params, function (err, response) {
            if (err) {
                res.send(JSON.stringify(err));
            } else {
                res.send(response.Location);
            }
        });
    });
}
/**
 * Asynchronously retrieves site settings from the database.
 * This function retrieves the site settings from db ,based on the CDN URL.
 * 
 * @returns {Promise<object>} A Promise that resolves with the site settings object if successful, or rejects with an error if unsuccessful.
 */
async function retrieveSiteSettings() {
    return new Promise((resolve, reject) => {
        // Querying the 'site_settings' collection in the database to find the settings associated with the configured CDN URL.
        semusiDb.collection('site_settings').findOne({"cdn": semusiConfig.cdnUrl}, (err, sitesettings) => {
            if (err ) {
                reject(err);
            } else {
                // If no error occurs and the settings are found, resolve the Promise with the retrieved site settings,
                // or an empty object if no settings are found.
                resolve(sitesettings || {});
            }
        });
    });
}

async function uploadCertificateS3(req, res, path, tmp_path, type) {
    try {

        if ((validateUploadFile(req.body.app_cert_name)) && (validateUploadFile(req.files.app_cert.name)) && (validateUploadFile(req.files.app_cert.path)) && (fileValidation('iosCert').includes(getFileExtension(req.files.app_cert.path)) && fileValidation('iosCert').includes(getFileExtension(req.body.app_cert_name)))) {
            var target_path = '';
            var bucketName, blobContainerCDN;

            if (semusiConfig.IsProduction) {
                bucketName = semusiConfig.S3_PROD_CERTBUCKET;
                blobContainerCDN = semusiConfig.blobContainerCDN + bucketName
            }
            else {
                bucketName = semusiConfig.S3_STAGING_CERTBUCKET;
                blobContainerCDN = semusiConfig.blobContainerCDN + bucketName
            }

            const blobService = Azure.createBlobServiceWithSas(semusiConfig.azureApiBlobSASURL, semusiConfig.azureApiStorageSASToken);
            var bucket = bucketName;
            var keyVar = path;

            await blobService.createBlockBlobFromLocalFile(bucket,
                keyVar,
                tmp_path,
                (error, result) => {
                    if (error) {
                        // Handle blob error
                        res.send('');
                    } else {
                        logger.info(`result => ${JSON.stringify(result)}`);
                        logger.info('Upload is successful');
                        res.send(blobContainerCDN + "/" + keyVar);
                    }
                }
            );
        } else {
            logger.error("Failed to upload Certs => Please Enter Only .p8 or .p12 Certificate Files")
            res.status(400).send("Invalid file format. Only .p8 or .p12 files are allowed.");
        }
    } catch (error) {
        logger.error(`error in uploadCertificateS3 ${error}`)
        res.status(400).send("something went wrong ");
    }
}

var auth = function (user, pass, callback) {
    var password = shaFunction(pass);
    semusiDb.collection('members').findOne({ "username": user, "password": password }, function (err, member) {
        callback(null, member);
    });
};

router.get('/api-key', auth, function (req, res, next) {
    if (req.user) {
        res.send(req.user.api_key);
    } else {
        res.send("-1");
    }
});

router.post('/reset', csrfProtection, function (req, res, next) {

     let password;
     let confirmPassword;
    if (semusiConfig.shaV1Hash == 'sha256') {
        password = shaFunction(req.body.password);
        confirmPassword = shaFunction(req.body.again);
    } else {
        password = shaFunction(processString(req.body.password));
        confirmPassword = shaFunction(processString(req.body.again));
    }
    const errors = validationResult(req);

    if (!errors.isEmpty()) {
        const alert = errors.array();
        renderResetPage(req,res,alert, req.query.prid)
    } else if (password !== confirmPassword) {
        renderResetPage(req,res, [{ msg: 'Passwords do not match.' }], req.query.prid)
    } else {
        res.expose(semusiConfig.serverName, "serverName");
        if (password && confirmPassword && req.body.prid) {
            semusiDb.collection('password_reset').findOne({ prid: req.body.prid }, function (err, passwordReset) {
                semusiDb.collection('members').updateOne({ _id: semusiDb.ObjectID(passwordReset.user_id) }, { '$set': { "password": password }, '$unset': { 'systemPassword': 1 } }, function (err, member) {
                    req.flash('info', 'reset.result');
                    res.redirect('/login');
                });

                semusiDb.collection('members').findOne({ _id: passwordReset.user_id }, function (err, member) {
                    if (member) {
                        semusiMail.sendPasswordSuccessResetInfo(member);
                    }
                });

                semusiDb.collection('password_reset').remove({ prid: req.body.prid }, function () { });
            });

        } else {
            renderResetPage(req,res,'', req.body.prid)
        }
    }
});
router.get('/check-email-existence', async function (req, res, next) {
    // Get the email from the request query, after decoding and sanitizing it
    const buffEmail = req.query.buffEmail;
    const authType = req.query.selectedButton === 'login_Email' ? 'BASIC' : 'SSO';
    let email = xss(processString(buffEmail));
     // Check if the request origin is allowed
    if (req.headers['origin'] == undefined || req.headers['origin'] == 'null' || (req.headers['origin'].split(",").length == 1 && req.headers['origin'] == semusiConfig.cdnUrl)) {
          // Get the authentication provider
          let provider;
      
          provider = authProv.createProvider(authType);
          const typeAuthProv = await provider.getProvider(req.query.selectedButton === 'login_Email' ? undefined:  semusiConfig.cdnUrl);
         // Call the provision function to check if the email exists
        const response = await typeAuthProv.provision({ email: email })
        res.json(response);
    } else {
            // If the request origin is not allowed, return a 403 error
        res.status(403).send({ Error: 'Forbidden! Cross Origin Policy' })
    }
});


router.post('/forgot', csrfProtection, [check('email', 'email is not valid').isEmail().normalizeEmail()], function (req, res, next) {
    let email = xss(req.body.email);
    const errors = validationResult(req);
    if (!errors.isEmpty()) {
        const alert = errors.array();
        return renderForgotPage(req, res, alert, '');
    }

    // Validate CAPTCHA only if captchaEnabled is true
    if (req.session.captchaEnabled) {
        const captchaResponse = xss(req.body.captcha);
        
        if (captchaResponse !== req.session.captcha) {
            const message = 'Incorrect CAPTCHA. Please try again.';
            return renderForgotPage(req, res, "", message);
        }
    }
    res.expose(semusiConfig.serverName, "serverName");
    const hostname = req.headers.host;  // hostname = 'localhost:8080'

    if (email) {
        const emailQuery = { 'email': { $regex: new RegExp('^' + email, 'i') } };
        semusiDb.collection('members').findOne(emailQuery, function (err, member) {
            if (member) {
                const timestamp = Math.round(new Date().getTime() / 1000);
                const prid = shaFunction(member.username + member.full_name, timestamp);

                semusiDb.collection('password_reset').insert({ "prid": prid, "user_id": member._id, "timestamp": timestamp }, { safe: true }, function (err, password_reset) {
                    semusiMail.sendPasswordResetInfo(hostname, member, prid);
                    return renderForgotPage(req, res, '', "Please check your email for the reset password link.");
                });
            } else {
                return renderForgotPage(req, res, '', "Please enter correct email address");
            }
        });
    } else {
        res.redirect('/forgot');
    }
});


router.post('/signup', csrfProtection, [
    check('password', 'please enter valid password').isLength({ min: 5 }),
    check('h_fullname').isLength({ min: 3 }).withMessage('Name must be of 3 characters long.'),
    check('hemail').notEmpty().isBase64()
], async function (req, res, next) {
        // Check for Cross-domain Policy with Untrusted Domains 
    if (req.headers['origin'] == undefined || req.headers['origin'] == 'null' || (req.headers['origin'].split(",").length == 1 && req.headers['origin'] == semusiConfig.cdnUrl)) {
        res.expose(semusiConfig.serverName, "serverName");
        let email = xss(processString(req.body.hemail));
        let full_name = xss(processString(req.body.h_fullname));
        let password = xss(req.body.password);
        const errors = validationResult(req);
        if (!errors.isEmpty()) {
            const alert = errors.array();
             renderSignupPage(req,res,alert,'' )
        } else {

            // Validate CAPTCHA only if captchaEnabled is true
        if (req.session.captchaEnabled) {
        const captchaResponse = xss(req.body.captcha);
        
        if (captchaResponse !== req.session.captcha) {
            const message = 'Incorrect CAPTCHA. Please try again.';
            return renderSignupPage(req, res, "", message);
        }
    }
            var emailParts = email.split('@');
                //Incase of Ad We don't need to split the email and its domain
            var domainInitial = (emailParts[1]) ? emailParts[1].split('.')[0] : '';
            var domainindex = (domainInitial !== "" ) ? semusiConfig.Domains.indexOf(domainInitial) : -1 ;
            logger.info("domain : " + domainInitial);

                      // get siteSettings from the common function
                      const siteSettings = await retrieveSiteSettings();


                      if (domainindex == -1) {
                    // if ad based Auth
                if (siteSettings && siteSettings.sso_type == "ad" && req.body.selectedButton == 'SSO') {
                    // Decode the string only
                    password = processString(req.body.password);
                } else {
                        // continue without exisitng way to login
                    if (semusiConfig.shaV1Hash == 'sha256') {
                        password = shaFunction(password);
                    } else {
                        password = shaFunction(processString(password));
                    }
                }
                let provider;
                let authType = req.body.selectedButton === 'login_Email' ? 'BASIC' : 'SSO';

                provider = authProv.createProvider(authType);
                const typeAuthProv = await provider.getProvider(req.body.selectedButton === 'login_Email' ? undefined : semusiConfig.cdnUrl);

                const signresponse = await typeAuthProv.signup({ email, password, full_name });

                    //if signup is done proper redirect to thankyou page 
                if(signresponse.acknowledged){
                    res.redirect('/thankyou');
                } else {
                    renderSignupPage(req, res, '', "An error occurred while creating a user.");
                }
            } else {
                let message = domainInitial + " is not an allowed domain";
                renderSignupPage(req, res, '', message);
            }
        }
    } else {
        res.status(403).send({ Error: 'Forbidden! Cross Origin Policy' });
    }
});


//  two factor /authentication 
//         @description : 
//         checks if otp is already present  if found then check time and update otp , sends email otherwise ask user to wait for one minute
//                         if otp is not found  then insert otp and sends mail 
//  @params email: Email of the user , req and res of post method 

function startTwoFactorAuth(emailId, req, res) {
    let timestamp = Date.now();
    //GENERATE OTP
    var random = arbit();
    var digits = '0123456789';
    let OTP = '';
    for (let i = 0; i < 6; i++) {
        OTP += digits[random.nextInt(0, 9)];
    }
    // Check In the OTP Collection  IF its already there
    semusiDb.collection('otp_verification').findOne({ "email": emailId }, function (err, data) {
        // If otp not found
        if (!data || data == null) {
            // Insert Otp into db 
            semusiDb.collection('otp_verification').insert({ otp: OTP, email: emailId, timestamp: timestamp, loggedIn_Count: 0 }, function (err, data) {
                if (!err || data) {
                    // Send email to the user
                    semusiMail.sendAuthInfo(emailId, OTP)
                    res.redirect('/authentication')
                }
            });
        } else {
            // IF Otp is in db
            const curr_timestamp = Date.now();
            const ONE_MIN = 1 * 60 * 1000;
            //check difference between current time  and time of found OTP
            if ((curr_timestamp - data.timestamp) > ONE_MIN) {
                // Update otp in the Db
                semusiDb.collection('otp_verification').update({ "email": emailId },
                    { $set: { otp: OTP, email: emailId, timestamp: timestamp, loggedIn_Count: 0 } }, function (err, data) {
                        if (!err || data) {
                            // Sends Email to the user
                            semusiMail.sendAuthInfo(emailId, OTP)
                            res.redirect('/authentication')
                        }
                    });
            } else {
                renderAuthenticationPage(req,res,'','', false, false, true ,false, false  )
            }
        }
    });

}

//end Two factor Authentication 
router.post('/login', csrfProtection, [
    check('password', 'Please enter a valid password').isLength({ min: 5 }),
    check('email').notEmpty(),
], async function (req, res, next) {
    const errors = validationResult(req);

    // Check for Cross-domain Policy with Untrusted Domains
    if (req.headers['origin'] == undefined || req.headers['origin'] == 'null' || (req.headers['origin'].split(",").length == 1 && req.headers['origin'] == semusiConfig.cdnUrl)) {

        if (!errors.isEmpty()) {
            const alert = errors.array();
            renderLoginPage(req, res, '', alert);
        } else {
            res.expose(semusiConfig.serverName, "serverName");
            if (req.body.email && req.body.password) {

                // CAPTCHA validation
                if(req.session.captchaEnabled){
                    const captchaResponse = xss(req.body.captcha);
                    if (captchaResponse !== req.session.captcha) {
                        const message = 'Incorrect CAPTCHA. Please try again.';
                        return renderLoginPage(req, res, message, "");
                    }
                }
                   

                // Get siteSettings from the common function
                const siteSettings = await retrieveSiteSettings();

                // If AD-based Auth
                if (siteSettings && siteSettings.sso_type === "ad" && req.body.selectedButton === 'SSO') {
                    // Decode the string only
                    password = processString(req.body.password);
                } else {
                    // Continue with the existing way to login
                    if (semusiConfig.shaV1Hash === 'sha256') {
                        password = shaFunction(req.body.password);
                    } else {
                        password = shaFunction(processString(req.body.password));
                    }
                }

                const email = processString(req.body.email);
                let provider;
                let authType = req.body.selectedButton === 'login_Email' ? 'BASIC' : 'SSO';

                provider = authProv.createProvider(authType);
                const typeAuthProv = await provider.getProvider(req.body.selectedButton === 'login_Email' ? undefined : semusiConfig.cdnUrl);

                const response = await typeAuthProv.login({ email: email, password, domain: semusiConfig.cdnUrl });

                return handlePostAuthLogin(req, res, response);

            } else {
                renderLoginPage(req, res, "Wrong Username or password");
                res.end();
            }
        }

    } else {
        res.status(403).send({ Error: 'Forbidden! Cross Origin Policy' });
    }
});

  // Handle the SAML callback route
router.post('/login/callback', function (req, res, next) {

    authenticateSaml(req, res, async function (err) {
        if (err) {
            return res.redirect('/login'); // Example: Redirect to login page on error
        }
        // Get the authentication provider instance
        const provider = authProv.createProvider("SSO")
        const typeAuthProv =  await provider.getProvider(semusiConfig.cdnUrl)

        const email = req.user.email
        const password = ''



        // Login Function of ts-Core 
        const response = await typeAuthProv.login({ email: email, password,  domain: semusiConfig.cdnUrl });
        handlePostAuthLogin(req, res, response)

    });
});

router.get('/thankyou', function (req, res, next) {
    res.render('thankyou', { "message": "", "csrf": req.session._csrf, "serverName": semusiConfig.serverName, "cdnUrl": semusiConfig.cdnUrl });
});

router.get('/feedbackform', function (req, res, next) {
    res.render('feedbackform', { "message": "", "csrf": req.session._csrf, "serverName": semusiConfig.serverName, "cdnUrl": semusiConfig.cdnUrl });
});

router.get('/campaigns', function (req, res, next) {
    res.render('rcampaigns');
});

router.get('/privacypolicy', function (req, res, next) {
    res.render('privacypolicy');
});


router.get('/track', function (req, res, next) {
    res.render('track');
});

router.get('/test', function (req, res, next) {
    res.render('test');
});
router.get('/admindashboard', function (req, res, next) {
    if (!req.session.uid || !req.session.login_time) {
        res.redirect('/login');
    }

    var action = false;
    if (req.query.action) {
        action = req.query.action;
    }
    else {
        action = false;
    }

    res.render('admindashboard', { "memberId": req.session.uid, "action": action });
});

router.post('/dashboard/settings', function (req, res, next) {
    if (!req.session.uid || !req.session.login_time) {
        res.end();
        return false;
    }

    if (!isGlobalAdmin(req)) {
        res.end();
        return false;
    }

    var newAppOrder = req.body.app_sort_list;

    if (!newAppOrder || newAppOrder.length == 0) {
        res.end();
        return false;
    }

    semusiDb.collection('settings').update({}, { '$set': { 'appSortList': newAppOrder } }, { 'upsert': true });
});

router.post('/users/images', csrfProtection, formData.stream(), async function (req, res) {
    if (!req.files.user_image) {
        res.status(400).send("something went wrong ");
        return false;
    }
    try {

        const file = await FileType.fromStream(req.files.user_image);
        // Perform mime type validation
        if (!fileValidation('profileMimeTypes').includes(file.mime)) {
            return res.status(400).json({ error: 'Invalid file MIME type.' });
        }

        // Perform file type validation
        if (!fileValidation('profileFile').includes(file.ext)) {
            return res.status(400).json({ error: 'Invalid file type.' });
        }
        if ((validateUploadFile(req.body.file_name)) && fileValidation('profileFile').includes(getFileExtension(req.files.user_image.path)) && fileValidation('profileFile').includes(getFileExtension(req.body.file_name))) {

            var target_path = '';

            fs.mkdir(__dirname + '/public/users/', { recursive: true }, (err) => {
                if (err) {
                    logger.error(err);
                }
                target_path = __dirname + '/public/users/' + req.body.user_image_id + ".jpg";

                var tmp_path = req.files.user_image.path,
                    type = req.files.user_image.type;


                mv(tmp_path, target_path, function (err) {
                    fs.unlink(tmp_path, function () { });
                    res.send('/users/' + req.body.user_image_id + ".jpg");
                });
            });
        } else {
            logger.error("Failed to upload images => Please Enter Only .jpg, .jpeg, .png,  Files")
            res.status(400).send("Invalid file format. Only .jpg, .jpeg, .png, files are allowed.");
        }
    } catch (error) {
        logger.error(`error in profile upload ${error}`)
        res.status(400).send("something went wrong");
    }
});


router.post('/campaign/images', function (req, res) {
    if (!req.files.campaign_image) {
        res.end();
        return true;
    }

    var target_path = '';

    fs.mkdir(__dirname + '/public/campaignFiles/');
    var imgid = (new Date).getTime();
    target_path = __dirname + '/public/campaignFiles/' + imgid + ".jpg";

    var tmp_path = req.files.campaign_image.path,
        type = req.files.campaign_image.type;


    fs.rename(tmp_path, target_path, function (err) {
        fs.unlink(tmp_path, function () { });

        res.setHeader("Access-Control-Allow-Origin", "http://localhost:8181");
        res.send('/campaignFiles/' + imgid + ".jpg");
    });
});

async function uploadToAzure(filename, tmp_path, app_id, type) {

    try {
        var bucket = semusiConfig.minioBuckets.campaignImages, azureblobContainerCDN, objWithURL;
        azureblobContainerCDN = semusiConfig.azureblobContainerCDN;

        const blobService = Azure.createBlobServiceWithSas(semusiConfig.azureCDNBlobSASURL, semusiConfig.azureCDNSASToken);
        var keyVar = "uploads/campaignFiles/campaignimages/" + app_id + "/" + filename;
        await blobService.createBlockBlobFromLocalFile(bucket,
            keyVar,
            tmp_path,
            (error, result) => {
                if (error) {
                    // Handle blob error
                    logger.error(`error Failed IN AZURE=> ${JSON.stringify(error)}`);
                    return 'File upload Failed'
                } else {
                    logger.error(`SUCCESS IN AZURE====>`);
                    return "SUCESS"
                }
            });
    } catch (error) {
        logger.error(`error in azure upload ${error}`);
    }
}
function uploadToE2E(filename, tmp_path, app_id, type) {

    if (!getfileuploaded(filename, type, app_id, tmp_path)) {
        logger.error(`SUCCESS IN E2E====>`);
        return "SUCESS"
    } else {
        logger.error(`ERROR IN AZURE====`);

        return 'File upload Failed'
    }
}
router.post('/campaignFiles/campaignimagesAWS', function (req, res) {
    if (!req.files.image) {
        res.end();
        return true;
    }

    var tmp_path = req.files.image.path,
        filename = req.files.image.name,
        type = req.files.image.type,
        app_id = req.body.appid;

    AWS.config.region = semusiConfig.AWS_REGION;
    AWS.config.update({ accessKeyId: semusiConfig.AWSLAMBDA_ACCESS_KEY_ID, secretAccessKey: semusiConfig.AWSLAMBDA_SECRET_KEY });

    // if get filename and type undefind
    if (filename === undefined) {
        var ags = tmp_path.split("/");
        ags = ags[ags.length - 1];
        ags = ags.split(".");
        filename = ags[0];
        type = ags[ags.length - 1];
    }

    var s3bucket = new AWS.S3();
    var bucket = semusiConfig.minioBuckets.campaignImages;
    filename = moment.utc() + '_' + filename + '.' + type;
    var keyVar = "uploads/campaignFiles/campaignimages/" + app_id + "/" + filename;

    s3bucket.createBucket({ Bucket: bucket }, function (err, data) {
        logger.info("bucket creation: " + err ? "FAIL" : "SUCCESS");
        var fileBuffer = fs.readFileSync(tmp_path);
        var params = { ACL: 'public-read', Bucket: bucket, keyVar: keyVar, Body: fileBuffer, ContentType: type };
        s3bucket.upload(params, function (err, response) {
            if (err) {
                res.send('');
            } else {
                res.send(response.Location);
            }
        });
    });
});

async function uploadAssets(filename, tmp_path, app_id, type) {
    await semusiConfig.uploadAssets.forEach(async (uploadTo) => {
        switch (uploadTo) {
            case "E2E":
                uploadToE2E(filename, tmp_path, app_id, type)
                break;
            case "Azure":
                await uploadToAzure(filename, tmp_path, app_id, type)
                break;
            default:
                logger.error("No Sequence Found for Upload")

        }
    })
}

router.post('/campaignFiles/campaignimages', csrfProtection, formData.stream(), async (req, res) => {

    if (!req.files.XMLmetadataFile && !req.files.image) {
        res.status(400).send("something went wrong ");
        return false;
    }
    try {

        // For the case of XML only
        if(req.body.XML == 'true'){
            // upload the file to the path 
            const target_path = path.join(__dirname, '/public/appcertificates/common/', req.body.XMLmetadataFile.originalFilename)
            uploadFileToDestination( req.files.XMLmetadataFile.path,target_path)

            // update the name to the db in the site_settings 
            const update = { $set: { 'xml_fileName':req.body.XMLmetadataFile.originalFilename } };
            updateSiteSettings(update);
            // return the flow
            res.send("uploaded")
            return
        }



        // Case of Upload Image for custom Logo in settings
        if(req.body.customLogo == 'true'){
            const targetPath = path.join(__dirname, '/public/assets/img/', req.body.image.originalFilename);
            uploadFileToDestination( req.files.image.path,targetPath)
        }
        const file = await FileType.fromStream(req.files.image);

        // Perform MIME type validation
        if (!fileValidation('campaignMimeTypes').includes(file.mime)) {
            return res.status(400).json({ error: 'Invalid file MIME type.' });
        }

        // Perform file type validation
        if (!fileValidation('campaignFileExtension').includes(file.ext)) {
            return res.status(400).json({ error: 'Invalid file type.' });
        }
        if ((validateUploadFile(req.body.image_id)) && fileValidation('campaignFileExtension').includes(getFileExtension(req.files.image.path)) && fileValidation('campaignFileExtension').includes(getFileExtension(req.body.image_id))) {

            var tmp_path = req.files.image.path,
                filename = req.files.image.name,
                type = req.files.image.type,
                app_id = req.body.appid;
            // if get filename and type undefind
            let rawFileName;
            if (filename === undefined) {
                var ags = tmp_path.split("/");
                ags = ags[ags.length - 1];
                ags = ags.split(".");
                rawFileName = ags[0];
                type = ags[ags.length - 1];
            }
            // create file name 
            rawFileName = moment.utc() + '_' + rawFileName;
            filename = rawFileName + '.' + type;

            var base = semusiConfig.blobContainerCDN
            // create ReturnObj from filename and BaseUrl 
            if (semusiConfig.uploadAssets[0] == "Azure") {
                base = semusiConfig.blobContainerCDN + app_id + "/"
            }
            var returnObj = { url: filename, baseURL: base }

            // check the seq in which needs to be uploaded ---=================================================================================//......
            if (type === "gif") {
                gifFrames(
                    { url: tmp_path, frames: 'all', outputType: 'png', cumulative: true },
                    async function (err, frameData) {
                        if (err) {
                            throw err;
                        } else {

                            let paths = await Promise.all(frameData.map(async function (frame) {
                                let splitPath = tmp_path.split("/");
                                let folderName = `/${splitPath[1]}/`;
                                const path = `${folderName}${rawFileName}-` + frame.frameIndex + '.png';
                                const writeStream = fs.createWriteStream(path);
                                const readStream = frame.getImage();
                                readStream.pipe(writeStream);
                                await (new Promise((resolve, reject) => stream.finished(writeStream, (err) => resolve(err))));
                                return path
                            }));

                            // Upload the original GIF file
                            await uploadAssets(rawFileName + '.gif', tmp_path, app_id, 'gif');
                            returnObj.imgs = await Promise.all(paths.map(async path => {
                                var ags = path.split("/");
                                ags = ags[ags.length - 1];
                                ags = ags.split(".");
                                let rawFileName = ags[0];
                                let type = ags[ags.length - 1];
                                let filename = rawFileName+'.'+type
                                await uploadAssets(filename, path, app_id, type);
                                return filename;
                            }));
                            returnObj.type = type;
                            returnObj.fe = "png";
                            res.send(returnObj);
                        }

                    }
                );
            } else {
                await uploadAssets(filename, tmp_path, app_id, type);
                returnObj.type = type;

                if(req.body.customLogo == 'true'){
                    const update = { $set: { 'logo_name': req.body.image.originalFilename , logo_url: returnObj.url } };
                    updateSiteSettings(update);
                    res.send(returnObj);
                }else{
                    res.send(returnObj);
                }
            }
        } else {
            logger.error("Failed to upload images => Please Enter Only .jpg, .jpeg, .png, .gif Files")
            res.status(400).send("Invalid file format. Only .jpg, .jpeg, .png, .gif files are allowed.");
        }
    } catch (error) {
        logger.error(`campaign images ${error}`)
        res.status(400).send("something went wrong");
    }

});
//Upload Files to E2E
function getfileuploaded(filename, type, app_id, tmp_path) {
    // Instantiate the minio client with the endpoint
    // and access keys as shown below.
    let status = false;
    var minioClient = new Minio.Client({
        endPoint: semusiConfig.endPoint,
        useSSl: semusiConfig.useSSL,
        accessKey: semusiConfig.accessKey,
        secretKey: semusiConfig.secretKey
    });
    if (semusiConfig.minioPort) {
        minioClient.port = semusiConfig.minioPort;
    }
    // Using fPutObject API upload your file to the bucket.
    minioClient.fPutObject(semusiConfig.minioBuckets.campaignImages, filename, tmp_path, function (err, etag) {
        logger.info(etag);
        if (err) {
            logger.error("Error occurend in image upload =>" + err);
            status = false;
        }
        status = true;
    });
    return status;
}


router.post('/apps/certificate', csrfProtection, function (req, res) {
    if (!req.files.app_cert || !req.body.app_cert_id || !req.body.app_cert_name) {
        res.status(400).send("something went wrong ");
        return false;
    }
    try {

        // destructure req.body
        const { app_cert_name ,app_cert_id ,isdev, platform } = req.body;

        // destructure req.files
        const { path, name } = req.files.app_cert;
                            
        let target_path = ''
        // validate file, filename and its extension from a common function
        if (validateFileAndExtension(app_cert_name, path, name, platform) ) {
            fs.mkdir(__dirname + '/public/appcertificates/' + app_cert_id, { recursive: true }, (err) => {
                if (err) logger.error("error in mkdir", err);
                target_path = __dirname + '/public/appcertificates/' + app_cert_id + '/' + app_cert_name;
                const tmp_path = path;

                mv(tmp_path, target_path, (err) => {
                    if (err) {
                        logger.error(err);
                    }

                    fs.unlink(tmp_path, function () { });
                    res.status(200).send("File uploaded successfully in the App folder.");
                    const fileData = fs.readFileSync(target_path, "utf-8");
                    const isModeDev = isdev;
                    updateCertificateToDb(isModeDev, app_cert_id, app_cert_name, fileData,platform);
                });

            });
        } else {
            logger.error("Failed to upload Certs => Please Enter Only .p8 or .p12 Certificate Files")
            res.status(400).send("Invalid file format. Only .p8 or .p12 files are allowed.");
        }

    } catch (error) {
        logger.error("Failed to upload Certs")
        res.status(400).send("something went wrong ");
    }
});


router.get('/events', function (req, res, next) {
    res.render('events', { "csrf": req.session._csrf, "prid": req.body.prid });
});

/**
* @description: Returns Current display pref data.
*/
router.get('/getDisplayPref', (req, res, next) => {
    semusiDb.collection('members').findOne({ "_id": semusiDb.ObjectID(req.session.uid) }, (err, data) => {
        if (err) throw err;
        if (Object.keys(data).length) {
            res.status(200).json({
                status: true,
                data: data.displayPref
            });
        } else {
            res.status(404).json({
                status: false,
                msg: 'Data not exist'
            });
        }
    });
});

/**
* @description: Update Current display pref data.
*/

router.patch('/updateDisplayPref', (req, res, next) => {
    const prefData = req.body.prefData;
    semusiDb.collection('members').update({ "_id": semusiDb.ObjectID(req.session.uid) }, { $set: { "displayPref": prefData } }, (err, data) => {
        if (err) throw err;
        if (data.result.ok) {
            res.status(200).json({
                status: true,
                "msg": "Successfully updated"
            })
        }
        else {
            res.status(400).json({
                status: false,
                msg: 'Error occured while update'
            })
        }
    })
})

module.exports = router;
