require "lfs"
local utils = require "rasa.utils"

module(..., package.seeall)

local function GetBasePath ()
	return "/var/lib/inconcert/rasa/vccs/"
end

local function GetTemplatesVccPath ()
	return "/usr/local/share/lua/5.1/rasa/templates/vcc/"
end

local function CreateDirectory (directoryName)
	local alreadyExist = isDirectory(directoryName)
	if alreadyExist then
		return false, {result = "UNABLE TO CREATE DIRECTORY. DIRECTORY ALREADY EXIST", directory = directoryName}
	end
	local commandLine = "mkdir -p " .. directoryName
	LogInfo("[RASA_FILESYSTEM:CreateDirectory] Creating directory %s.", commandLine)
	os.execute(commandLine)
	return true
end

local function CopyTreeDirectoryWithContent (source, target)
	local commandLine = ("cp -avr %s %s"):format(source, target)
	LogInfo("[RASA_FILESYSTEM:CopyTreeDirectoryWithContent] Copying directory structure with content. Command %s.", commandLine)
	os.execute(commandLine)
end

local function MoveDirectory (source, target)
	local commandLine = ("mv %s* %s"):format(source, target)
	LogInfo("[RASA_FILESYSTEM:MoveDirectory] Moving directory. %s.", commandLine)
	os.execute(commandLine)
end

function RemoveDirectory (directoryName)
	if not directoryName then
		return false, {}
	end
	local exist = isDirectory(directoryName)
	if not exist then
		return false, {result = "UNABLE TO REMOVE DIRECTORY. DIRECTORY DOES NOT EXIST", directory = directoryName}
	end
	local commandLine = ("rm -rf %s"):format(directoryName)
	LogInfo("[RASA_FILESYSTEM:RemoveDirectory] Removing directory. %s.", commandLine)
	os.execute(commandLine)
	return true
end

function RemoveFile (fullFileName)
	if not fullFileName then
		return false, {}
	end
	local commandLine = ("rm %s"):format(fullFileName)
	LogInfo("[RASA_FILESYSTEM:RemoveFile] Removing file. %s.", commandLine)
	os.execute(commandLine)
	return true
end

function CreateFile (fullFileName, content)
	assert(fullFileName)
	assert(content)

	LogInfo("[RASA_FILESYSTEM:CreateFile] fullFileName file. %s content %s.", fullFileName, content)
	local f, result = io.open(fullFileName, "wb")
	if not f then
		local response = {result = "ERROR CREATING TXT FILE", file = fullFileName, err = result}
		return false, response
	end
	f:write(content)
	f:close()

	return true, {}
end

function WriteTxtFile (fullFileName, content)
	return CreateFile(fullFileName, content)
end

--[[
	baseDir           = /var/lib/inconcert/rasa/vccs/
	vccDir            = /var/lib/inconcert/rasa/vccs/vcc2/
	appVccDir         = /var/lib/inconcert/rasa/vccs/vcc2/test_rasa_app14/
	domainDir         = /var/lib/inconcert/rasa/vccs/vcc2/test_rasa_app14/
	modelDir          = /var/lib/inconcert/rasa/vccs/vcc2/test_rasa_app14/models/
	dataDir           = /var/lib/inconcert/rasa/vccs/vcc2/test_rasa_app14/data/
	nluName           = nlu.md
	fullNLUName       = /var/lib/inconcert/rasa/vccs/vcc2/test_rasa_app14/data/nlu.md
	configYmlName     = config.yml
	fullConfigYMLName = /var/lib/inconcert/rasa/vccs/vcc2/test_rasa_app14/config.yml
]]--
function GetVccAppDirectories (vcc, appId)
	assert(vcc)
	assert(appId)

	vcc = vcc:lower()
	appId = utils.SanitizeAppId(appId):lower()

	local baseDir       = GetBasePath()
	local vccDir        = string.lower(baseDir .. vcc .. "/")
	local appVccDir     = string.lower(vccDir .. appId .. "/")
	local domainDir     = appVccDir
	local modelDir      = string.lower(appVccDir .. "models/")
	local dataDir       = string.lower(appVccDir .. "data/")
	local configYmlName = "config.yml"
	local nluName       = "nlu.md"

	local info = {
		baseDir           = baseDir,
		vccDir            = vccDir,
		appVccDir         = appVccDir,
		modelDir          = modelDir,
		domainDir         = domainDir,
		dataDir           = dataDir,
		nluName           = nluName,
		fullNLUName       = dataDir .. nluName,
		configYmlName     = configYmlName,
		fullConfigYMLName = appVccDir .. configYmlName
	}
	--LogDebug("[RASA_FILESYSTEM:GetVccAppDirectories] Directories %s.", json.encode(info))
	return info
end

function CreateAppFileSystemStructure (data)
	local directoryName = data.name
	if data.imported then
		directoryName = data.sourceImportedApp.exportedAppId
	end

	local directories = GetVccAppDirectories(data.vcc, directoryName)
	LogInfo("[RASA_FILESYSTEM:CreateAppFileSystemStructure] Creating App file system structure. app %s, vcc %s, directories: %s.", data.name, data.vcc, json.encode(directories or {}))

	local success, response = CreateDirectory(directories.appVccDir)
	if not success then
		LogWarning("[RASA_FILESYSTEM:CreateAppFileSystemStructure] Unable to create Rasa App file system structure. Err: %s.", json.encode(response))
		return false, response
	end

	local sourceTemplate = GetTemplatesVccPath()
	CopyTreeDirectoryWithContent(sourceTemplate, directories.appVccDir)

	local temporalAppVccDir = directories.appVccDir .. "/vcc/"
	MoveDirectory(temporalAppVccDir, directories.appVccDir)
	RemoveDirectory(temporalAppVccDir)

	return true, {directories = directories}
end

function FileRead (fullFileName, returnType)
	--LogDebug("[RASA_FILESYSTEM:FileRead] Read file '%s' return type: '%s'.", fullFileName, returnType)

	local f = io.open(fullFileName)
	if not f then
		LogWarning("[RASA_FILESYSTEM:FileRead] Unable to open file: %s", fullFileName)
		return false, {errType = "UNABLE TO OPEN FILE"}
	end

	local f = io.open(fullFileName, "rb")
	local content

	if (returnType or ""):lower() == "table" then
		content = {}
		local k = 1
		for line in f:lines() do
			content[k] = line
			k = k + 1
		end
		--LogDebug(json.encode(content))
	else
		content = f:read("*a")
		--LogDebug("[RASA_FILESYSTEM:FileRead] content: %s", content)
	end

	f:close()
	return true, content
end

--[[
	Retorna el archivo en un array, y cada item del array es un parte de N Bytes.
]]--
function FileReadInParts (fullFileName)
	local blockBytes = (5 * 1024) * 1024 -- 5 Mb en bytes (5.242.880)
	local f = assert(io.open(fullFileName, "rb"))
	local content = {}
	local i = 0

	while true do
		i = i + 1
		local bytes = f:read(blockBytes)
		--LogDebug("%d - bytes %s", i, bytes)
		if not bytes then
			break
		end
		table.insert(content, bytes)
	end

	LogDebug("[RASA_FILESYSTEM:FileReadInParts] Readed file in parts. Block bytes '%d', total parts '%d', File: '%s' .", blockBytes, #content, fullFileName)

	--LogDebug("%s", #content, content[1])
	-- local tmpConten = table.concat(content)
	-- CreateFile("/var/lib/inconcert/rasa/vccs/vcc1/app1/models/borrame1.algo", tmpConten)

	return true, content
end

function isDirectory (directoryName)
	assert(type(directoryName) =="string")
	LogInfo("[RASA_FILESYSTEM:isDirectory] Validating Directory. directoryName: %s.", directoryName)

	local currentdir = lfs.currentdir()
	local is = lfs.chdir(directoryName) and true or false
	lfs.chdir(currentdir)

	return is
end

function CopyFile (source, target)
	local commandLine = ("cp %s %s"):format(source, target)
	LogInfo("[RASA_FILESYSTEM:CopyFile] Copying file. Command %s.", commandLine)
	os.execute(commandLine)
end

function DeleteFile (fullFileName)
	local commandLine = ("rm %s"):format(fullFileName)
	LogInfo("[RASA_FILESYSTEM:DeleteFile] Deleting file. Command %s.", commandLine)
	os.execute(commandLine)
end
