var fs = require('fs')
var exec = require('child_process').exec
module.exports = function(s,config,lang,app,io){
    if(config.dropInEventServer === true){
        if(config.dropInEventForceSaveEvent === undefined)config.dropInEventForceSaveEvent = true
        if(config.dropInEventDeleteFileAfterTrigger === undefined)config.dropInEventDeleteFileAfterTrigger = true
        var fileQueueForDeletion = {}
        var fileQueue = {}
        var search = function(searchIn,searchFor){
            return searchIn.indexOf(searchFor) > -1
        }
        var getFileNameFromPath = function(filePath){
            fileParts = filePath.split('/')
            return fileParts[fileParts.length - 1]
        }
        var clipPathEnding = function(filePath){
            var newPath = filePath + ''
            if (newPath.substring(newPath.length-1) == "/"){
                newPath = newPath.substring(0, newPath.length-1);
            }
            return newPath;
        }
        var processFile = function(filePath,monitorConfig){
            var ke = monitorConfig.ke
            var mid = monitorConfig.mid
            var filename = getFileNameFromPath(filePath)
            if(search(filename,'.jpg') || search(filename,'.jpeg')){
                var snapPath = s.dir.streams + ke + '/' + mid + '/s.jpg'
                fs.unlink(snapPath,function(err){
                    fs.createReadStream(filePath).pipe(fs.createWriteStream(snapPath))
                    s.triggerEvent({
                        id: mid,
                        ke: ke,
                        details: {
                            confidence: 100,
                            name: filename,
                            plug: "dropInEvent",
                            reason: "ftpServer"
                        },
                    },config.dropInEventForceSaveEvent)
                })
            }else{
                var reason = "ftpServer"
                if(search(filename,'.mp4')){
                    fs.stat(filePath,function(err,stats){
                        if(err)return;
                        var startTime = stats.ctime
                        var endTime = stats.mtime
                        var shinobiFilename = s.formattedTime(startTime) + '.mp4'
                        var recordingPath = s.getVideoDirectory(monitorConfig) + shinobiFilename
                        var writeStream = fs.createWriteStream(recordingPath)
                        fs.createReadStream(filePath).pipe(writeStream)
                        writeStream.on('finish', () => {
                            s.insertCompletedVideo(s.group[monitorConfig.ke].rawMonitorConfigurations[monitorConfig.mid],{
                                file: shinobiFilename,
                                events: [
                                    {
                                      id: mid,
                                      ke: ke,
                                      time: new Date(),
                                      details: {
                                          confidence: 100,
                                          name: filename,
                                          plug: "dropInEvent",
                                          reason: "ftpServer"
                                      }
                                    }
                                ],
                            },function(){
                            })
                        })
                    })
                }
                var completeAction = function(){
                    s.triggerEvent({
                        id: mid,
                        ke: ke,
                        details: {
                            confidence: 100,
                            name: filename,
                            plug: "dropInEvent",
                            reason: reason
                        },
                        doObjectDetection: (s.isAtleatOneDetectorPluginConnected && s.group[ke].rawMonitorConfigurations[mid].details.detector_use_detect_object === '1')
                    },config.dropInEventForceSaveEvent)
                }
                if(search(filename,'.txt')){
                    fs.readFile(filePath,{encoding: 'utf-8'},function(err,data){
                        if(data){
                            reason = data.split('\n')[0] || filename
                        }else if(filename){
                            reason = filename
                        }
                        completeAction()
                    })
                }else{
                    completeAction()
                }

            }
        }
        var onFileOrFolderFound = function(filePath,deletionKey,monitorConfig){
          fs.stat(filePath,function(err,stats){
              if(!err){
                    if(stats.isDirectory()){
                        fs.readdir(filePath,function(err,files){
                            if(files){
                                files.forEach(function(filename){
                                    onFileOrFolderFound(clipPathEnding(filePath) + '/' + filename,deletionKey,monitorConfig)
                                })
                            }else if(err){
                                console.log(err)
                            }
                        })
                    }else{
                        if(!fileQueue[filePath]){
                            processFile(filePath,monitorConfig)
                            if(config.dropInEventDeleteFileAfterTrigger){
                                clearTimeout(fileQueue[filePath])
                                fileQueue[filePath] = setTimeout(function(){
                                    exec('rm -rf ' + filePath,function(err){
                                        delete(fileQueue[filePath])
                                    })
                                },1000 * 60 * 5)
                            }
                        }
                    }
                    if(config.dropInEventDeleteFileAfterTrigger){
                        clearTimeout(fileQueueForDeletion[deletionKey])
                        fileQueueForDeletion[deletionKey] = setTimeout(function(){
                            exec('rm -rf ' + deletionKey,function(err){
                                delete(fileQueueForDeletion[deletionKey])
                            })
                        },1000 * 60 * 5)
                    }
               }
           })
        }
        var createDropInEventsDirectory = function(){
            if(!config.dropInEventsDir){
                config.dropInEventsDir = s.dir.streams + 'dropInEvents/'
            }
            s.dir.dropInEvents = s.checkCorrectPathEnding(config.dropInEventsDir)
            //dropInEvents dir
            if(!fs.existsSync(s.dir.dropInEvents)){
                fs.mkdirSync(s.dir.dropInEvents)
            }
        }
        var getDropInEventDir = function(monitorConfig){
            var ke = monitorConfig.ke
            var mid = monitorConfig.mid
            var groupEventDropDir = s.dir.dropInEvents + ke
            var monitorEventDropDir = groupEventDropDir + '/' + mid + '/'
            return monitorEventDropDir
        }
        var onMonitorStop = function(monitorConfig){
            var ke = monitorConfig.ke
            var mid = monitorConfig.mid
            if(s.group[monitorConfig.ke].activeMonitors[monitorConfig.mid].dropInEventWatcher){
                s.group[monitorConfig.ke].activeMonitors[monitorConfig.mid].dropInEventWatcher.close()
                delete(s.group[monitorConfig.ke].activeMonitors[monitorConfig.mid].dropInEventWatcher)
                var monitorEventDropDir = getDropInEventDir(monitorConfig)
                s.file('deleteFolder',monitorEventDropDir + '*')
            }
        }
        var createDropInEventDirectory = function(e,callback){
            var directory = s.dir.dropInEvents + e.ke + '/'
            fs.mkdir(directory,function(err){
                s.handleFolderError(err)
                directory = s.dir.dropInEvents + e.ke + '/' + (e.id || e.mid) + '/'
                fs.mkdir(directory,function(err){
                    s.handleFolderError(err)
                    exec('rm -rf "' + directory + '*"',function(){})
                    callback(err,directory)
                })
            })
        }
        var onMonitorInit = function(monitorConfig){
            var ke = monitorConfig.ke
            var mid = monitorConfig.mid
            var groupEventDropDir = s.dir.dropInEvents + ke
            createDropInEventDirectory(monitorConfig,function(err,monitorEventDropDir){})
        }
        // FTP Server
        if(config.ftpServer === true){
            const authenticateConnection = (connection) => {
                return new Promise((resolve,reject) => {
                    var username = null;
                    s.debugLog('client connected: ' + connection.remoteAddress);
                    connection.on('command:user', function(user, success, failure) {
                      if (user) {
                        username = user;
                        success();
                      } else {
                        failure();
                      }
                    })

                    connection.on('command:pass', function(password, success, failure) {
                        s.basicOrApiAuthentication(username,password,function(err,user){
                            if(user){
                                connection._user = user
                                success(username);
                            } else {
                                failure();
                            }
                            resolve({
                                ok: !!user,
                                username: username,
                                password: password
                            })
                        })
                    })
                })
            }
            createDropInEventsDirectory()
            if(!config.ftpServerPort)config.ftpServerPort = 21
            if(!config.ftpServerUrl)config.ftpServerUrl = `ftp://0.0.0.0:${config.ftpServerPort}`
            config.ftpServerUrl = config.ftpServerUrl.replace('{{PORT}}',config.ftpServerPort)
            const ftpd = require('shinobi-ftpd')
            const ftpServer = new ftpd.FtpServer(config.ftpServerUrl, Object.assign({
                getInitialCwd: function(connection, callback) {
                    callback(null, s.dir.dropInEvents + '/' + connection._user.ke)
                },
                getRoot: function() {
                    return s.dir.dropInEvents
                },
                pasvPortRangeStart: 1025,
                pasvPortRangeEnd: 1050,
                allowUnauthorizedTls: true,
                uploadMaxSlurpSize: 7000
            },config.ftpServerOptions || {}))

            ftpServer.on('error', function(error) {
                s.debugLog(['FTP Server error:', error]);
            })

            ftpServer.on('client:connected', async (connection) => {
                const response = await authenticateConnection(connection)
                if(connection._user){
                    connection.cwd = s.dir.dropInEvents + connection._user.ke
                    connection.on('file:stor', async (eventType, data) => {
                        const fileName = data.file
                        const pathPieces = fileName.substr(1).split('/')
                        const groupKey = connection._user.ke
                        const monitorId = pathPieces[0]
                        const firstDroppedPart = pathPieces[1]
                        const monitorEventDropDir = s.dir.dropInEvents + groupKey + '/' + monitorId + '/'
                        const deleteKey = monitorEventDropDir + firstDroppedPart
                        onFileOrFolderFound(
                            monitorEventDropDir + firstDroppedPart,
                            deleteKey,
                            {
                                ke: groupKey,
                                mid: monitorId
                            }
                        )
                    })
                }else{
                    s.systemLog(`Failed FTP Login Attempt : ${response.username}/${response.password}`)
                    throw `Failed to Authenticate FTP : ${response.username}/${response.password}`;
                }
            })

            ftpServer.listen(config.ftpServerPort)
            s.systemLog(`FTP Server running on port ${config.ftpServerPort}...`)
        }
        //add extensions
        s.onMonitorInit(onMonitorInit)
        s.onMonitorStop(onMonitorStop)
    }
    // SMTP Server
    // allow starting SMTP server without dropInEventServer
    if(config.smtpServer === true){
        if(config.smtpServerHideStartTls === undefined)config.smtpServerHideStartTls = null
        var SMTPServer = require("smtp-server").SMTPServer;
        if(!config.smtpServerPort && (config.smtpServerSsl && config.smtpServerSsl.enabled !== false || config.ssl)){config.smtpServerPort = 465}else if(!config.smtpServerPort){config.smtpServerPort = 25}
        config.smtpServerOptions = config.smtpServerOptions ? config.smtpServerOptions : {}
        var smtpOptions = Object.assign({
            logger: config.debugLog || config.smtpServerLog,
            hideSTARTTLS: config.smtpServerHideStartTls,
            onAuth(auth, session, callback) {
                var username = auth.username
                var password = auth.password
                s.basicOrApiAuthentication(username,password,function(err,user){
                    if(user){
                        callback(null, {user: user.ke})
                    }else{
                        callback(new Error(lang.failedLoginText2))
                    }
                })
            },
            onRcptTo(address, session, callback) {
                var split = address.address.split('@')
                var monitorId = split[0]
                var ke = session.user
                if(s.group[ke] && s.group[ke].rawMonitorConfigurations[monitorId] && s.group[ke].activeMonitors[monitorId].isStarted === true){
                    session.monitorId = monitorId
                }else{
                    return callback(new Error(lang['No Monitor Exists with this ID.']))
                }
                callback()
            },
            onData(stream, session, callback) {
                if(session.monitorId){
                    var ke = session.user
                    var monitorId = session.monitorId
                    var details = s.group[ke].rawMonitorConfigurations[monitorId].details
                    var reasonTag = 'smtpServer'
                    var text = ''
                    stream.on('data',function(data){
                        text += data.toString()
                    }) // print message to console
                    stream.on("end", function(){
                        var contentPart = text.split('--PartBoundary12345678')
                        contentPart.forEach(function(part){
                            var parsed = {}
                            var lines = part.split(/\r?\n/)
                            lines.forEach(function(line,n){
                                var pieces = line.split(':')
                                if(pieces[1]){
                                    var nextLine = lines[n + 1]
                                    var keyName = pieces[0].trim().toLowerCase()
                                    pieces.shift()
                                    var parsedValue = pieces.join(':')
                                    parsed[keyName] = parsedValue
                                }
                            })
                            if(parsed['content-type'] && parsed['content-type'].indexOf('image/jpeg') > -1){
                                // console.log(lines)
                            }
                            if(parsed['alarm event']){
                                reasonTag = parsed['alarm event']
                            }else if(parsed.subject){
                                reasonTag = parsed.subject
                            }
                        })
                        s.triggerEvent({
                            id: monitorId,
                            ke: ke,
                            details: {
                                confidence: 100,
                                name: 'smtpServer',
                                plug: "dropInEvent",
                                reason: reasonTag
                            },
                            doObjectDetection: (s.isAtleatOneDetectorPluginConnected && details.detector_use_detect_object === '1')
                        },config.dropInEventForceSaveEvent)
                        callback()
                    })
                }else{
                    callback()
                }
            }
        },config.smtpServerOptions)
        if(config.smtpServerSsl && config.smtpServerSsl.enabled !== false || config.ssl && config.ssl.cert && config.ssl.key){
            var key = config.ssl.key || fs.readFileSync(config.smtpServerSsl.key)
            var cert = config.ssl.cert || fs.readFileSync(config.smtpServerSsl.cert)
            smtpOptions = Object.assign(smtpOptions,{
                secure: true,
                key: config.ssl.key,
                cert: config.ssl.cert
            })
        }
        var server = new SMTPServer(smtpOptions)
        server.listen(config.smtpServerPort,function(){
            s.systemLog(`SMTP Server running on port ${config.smtpServerPort}...`)
        })
    }
}
