require "LuaOrm.Date"
local json = require "cjson"
local utils = require "rasa.utils"
local rasa_models = require("rasa.models"):GetModels()
require "uuid"

module(..., package.seeall)

local m_instanceOwner
function SetOwner (instanceOwner)
	m_instanceOwner = instanceOwner
end

--[[
-----------------------------
MODELS - GET ENTITY INFO
-----------------------------
	Gets information about the entity model.

]]--
function GetAppEntity (info)
	assert(info)
	assert(info.id)
	assert(info.appId)
	assert(info.vcc)

	local encodedEntity = rasa_models.VCCs.GetEntity(info.vcc, info.appId, info.id)
	if not encodedEntity then
		local response = {result = "ENTITY DOES NOT EXIST", info = info}
		LogError("[RASA_ENTITIES:Get] Error getting APP ENTITY '%s' Error: '%s'", json.encode(info), json.encode(response))
		return false, response
	end

	LogInfo("[RASA_ENTITIES:GetAppEntity] Success get APP ENTITY '%s.", json.encode(info))

	--LogDebug("[RASA_ENTITIES:GetAppEntity] info: '%s', data: '%s'", json.encode(info), encodedEntity)
	return true, encodedEntity
end

--[[
]]--
local function StarProcessCreateEntityInApp (info)
	LogInfo("[RASA_ENTITIES:StarProcessCreateEntityInApp] Start Process Creating Entity in app %s.", json.encode(info))

	local keyspace = utils.GetAgentKeySpace()
	info.id = info.name:lower()

	local encodedApp = rasa_models.VCCs.GetApplication(info.vcc, info.appId, keyspace)
	if not encodedApp then
		keyspace:Close()
		return false, {result = "UNABLE TO CREATE ENTITY IN APP - APP DOES NOT EXIST", info = info}
	end

	local encodedOldEntity = rasa_models.VCCs.GetEntityByName(info.vcc, info.appId, info.name, keyspace)
	if encodedOldEntity then
		keyspace:Close()
		return false, {result = "UNABLE TO CREATE ENTITY - ENTITY ALREADY EXIST", info = info, alreadyEntity = json.decode(encodedOldEntity)}
	end
	
	local entityId = info.id
	local encodedCurrentEntity = rasa_models.VCCs.GetEntity(info.vcc, info.appId, info.id, keyspace)
	if encodedCurrentEntity then
		-- Esto se puede dar si la entidad que se esta creando, tiene el mimsmo id que una entidad que exite con el mismo id, pero se ha cambiado su nombre.
		entityId = ("%s_%s"):format(entityId, uuid.new())
		LogInfo("[RASA_ENTITIES:StarProcessCreateEntityInApp] Making random EntityId '%s' in app %s.", entityId, json.encode(info))
	end

	info.id = entityId
	info.typeId = 1 -- SIMPLE - por compatibilidad con LUIS
	info.fullId = utils.MakeEntityId(info.vcc, info.appId, entityId)
	info.createdDateTime = LuaOrm.Date:time()
	info.creatorUserId = info.userId or "ANONYMOUS"
	info.userId = nil

	rasa_models.VCCs.UpdateEntity(info.vcc, info.appId, entityId, info, keyspace)
	keyspace:Close()

	return true, info
end

--[[
-----------------------------
MODELS - CREATE ENTITY EXTRACTOR
-----------------------------
	Adds an entity extractor to the application.

]]--
function CreateAppEntity (info)
	assert(type(info) == "table")
	assert(info.vcc)
	assert(info.appId)
	assert(info.name)

	local success, response = StarProcessCreateEntityInApp(info)
	if not success then
		LogError("[RASA_ENTITIES:CreateAppEntity] Error creating APP ENTITY on info '%s' vcc: '%s'. Response: '%s'", info.appId, info.vcc, json.encode(response))
		return false, response
	end

	local entityId = response.id
	LogInfo("[RASA_ENTITIES:CreateAppEntity] Success created APP ENTITY '%s' vcc: '%s', entityId: '%s'.", info.appId, info.vcc, entityId)

	return true, entityId
end

--[[
]]--
local function StarProcessRenameAppEntity (info)
	LogInfo("[RASA_APPS:StarProcessRenameAppEntity] Start Process Renaming App ENTITY %s.", json.encode(info))

	local keyspace = utils.GetAgentKeySpace()

	local encodedApp = rasa_models.VCCs.GetApplication(info.vcc, info.appId, keyspace)
	if not encodedApp then
		keyspace:Close()
		return false, {result = "UNABLE TO RENAME ENTITY - APP DOES NOT EXIST", info = info}
	end

	local encodedOldEntity = rasa_models.VCCs.GetEntityByName(info.vcc, info.appId, info.name, keyspace)
	if encodedOldEntity then
		keyspace:Close()
		return false, {result = "UNABLE TO RENAME ENTITY - ENTITY ALREADY EXIST", info = info, alreadyEntity = json.decode(encodedOldEntity)}
	end

	local encodedEntity = rasa_models.VCCs.GetEntity(info.vcc, info.appId, info.entityId)
	local currentEntity = json.decode(encodedEntity)
	currentEntity.oldName = currentEntity.name
	currentEntity.name = info.name
	currentEntity.lastModifiedDateTime = LuaOrm.Date:time()
	currentEntity.lastModifiedUserId = info.userId or "ANONYMOUS"
	info.userId = nil

	rasa_models.VCCs.UpdateEntity(info.vcc, info.appId, info.entityId, currentEntity, keyspace)
	keyspace:Close()

	return true, info
end

--[[
-----------------------------
MODELS - RENAME ENTITY MODEL
-----------------------------
	Updates the name of an entity extractor.

]]--
function RenameAppEntity (info)
	assert(type(info) == "table")
	assert(type(info.entityId) == "string")
	assert(type(info.appId) == "string")
	assert(type(info.vcc) == "string")
	assert(type(info.name) == "string")

	local success, response = StarProcessRenameAppEntity(info)
	if not success then
		LogError("[RASA_ENTITIES:RenameAppEntity] Unable to Renaming APP ENTITY. Error: '%s'", json.encode(response))
		return false, response
	end

	LogInfo("[RASA_ENTITIES:RenameAppEntity] Success Renamed APP ENTITY %s.", json.encode(info))

	return true, response
end

--[[
]]--
local function StarProcessDeleteEntity (info)
	LogInfo("[RASA_APPS:StarProcessDeleteEntity] Start Process Deleting Entity %s.", json.encode(info))

	local encodedApp = rasa_models.VCCs.GetApplication(info.vcc, info.appId)
	if not encodedApp then
		return false, {result = "UNABLE TO DELETE ENTITY - APP DOES NOT EXIST", info = info}
	end

	local encodedEntity= rasa_models.VCCs.GetEntity(info.vcc, info.appId, info.id)
	if not encodedEntity then
		return false, {result = "UNABLE TO DELETE ENTITY - ENTITY DOES NOT EXIST", info = info}
	end

	local entity = json.decode(encodedEntity)
	rasa_models.VCCs.RemoveEntity(info.vcc, info.appId, info.id, entity.name)

	return true, info
end

--[[
-----------------------------
MODELS - DELETE ENTITY MODEL
-----------------------------

]]--
function DeleteAppEntity (info)
	assert(type(info) == "table")
	assert(info.vcc)
	assert(info.appId)
	assert(info.id)

	----
	local success, response = StarProcessDeleteEntity(info)
	if not success then
		LogError("[RASA_ENTITIES:DeleteAppEntity] Deleting APP ENTITY '%s' Error: '%s'", json.encode(info), json.encode(response))
		return false, response
	end

	LogInfo("[RASA_ENTITIES:DeleteAppEntity] Success deleted APP ENTITY %s.", json.encode(info))

	--LogDebug("[RASA_ENTITIES:DeleteAppEntity] response: '%s'", json.encode(response))
	return true, response
end
