require "LuaOrm.Date"
local m_json = require "cjson"
local m_cassandra = require "lua_cassandra"
local helpers = require "helpers"
local m_model = require "audits.model"

module(..., package.seeall)

helpers.logger.Enable(true)

local function init (options)
	-- cassandra
	--LogInfo("[Audits - init] parameters %s", m_json.encode(options))
	assert(options.cassandra, "options.cassandra is missing")
	assert(options.cassandra.host, "missing options.cassandra.host field")
	assert(options.cassandra.port, "missing options.cassandra.port field")
	m_cassandra.seed(options.cassandra.host, options.cassandra.port)
	m_model.SetDatasource({
		cassandra = m_cassandra
	})
	return true
end

local function GetElapsedTimeSec (start)
	return helpers.utils.ElapsedTime.GetElapsedTimeSec(start)
end

--[[

]]--
local function Create (params)
	--1 Get Paramaters
	assert(params, "params is missing")
	assert(params.entity, "missing params.entity field")
	assert(params.vcc, "missing params.VCC field")
	assert(params.user, "missing params.user field")
	assert(params.fieldKey, "missing params.fieldKey field")
	assert(params.connection, "missing params.connection field")

	local connection = params.connection
	params.connection = nil
	--LogDebug("[Audits - Create] Exist Connection %s", connection ~= nil)

	--LogDebug("[AUDIT:Create] (ENTRA) --> params: %s", m_json.encode(params))

	local oldFields = params.oldFields
	local newFields = params.newFields
	local entity = params.entity
	local vcc = params.vcc
	local admin = params.user
	local now = LuaOrm.Date()
	local timeStampStr = params.timeStampStr or now:toString("%Y-%m-%d %H:%M:%S")
	local date = params.date or now:toString("%Y-%m-%d")
	local fieldKey = params.fieldKey
	local subEntity = params.subEntity
	local operation = params.operation

	local dataToUpdate = params.dataToUpdate or {}
	dataToUpdate.timeStampStr = timeStampStr
	dataToUpdate.timeStamp = now:time()
	dataToUpdate.user = admin
	dataToUpdate.subEntity = subEntity

	--Solo si el operation es 'Update' obtengo las diferencias
	if operation then
		dataToUpdate.operation = operation
		dataToUpdate.currentFields = newFields
		dataToUpdate.beforeFields = oldFields
	elseif oldFields and newFields then
		dataToUpdate.operation = "Update"
		local has_changed, differences = helpers.utils.CompareJsonObjects(newFields, oldFields)
		--LogDebug("[Audits::Create] has_changed %s - differences %s", has_changed, m_json.encode(differences or {}))
		if has_changed then
			dataToUpdate.beforeFields = differences.beforeFields
			dataToUpdate.currentFields = differences.currentFields
		else
			return false
		end
	elseif oldFields and not newFields then
		dataToUpdate.operation = "Delete"
		dataToUpdate.beforeFields = oldFields
	elseif newFields and not oldFields then
		dataToUpdate.operation = "Create"
		dataToUpdate.currentFields = newFields
	else
		assert(newFields, "params newFields and oldFields are missing")
	end

	--LogDebug("[Audits - Create] NewRecord rowId %s entity %s fieldKey %s admin %s", rowId,entity , fieldKey, admin)
	m_model.NewRecord({
		vcc = vcc,
		date = date,
		data = dataToUpdate,
		entity = entity,
		fieldKey = fieldKey,
		user = admin,
		connection = connection
	})
	--LogDebug("[Audits - Create] END NewRecord ")
	return true
end

--[[
	1- VCC y Rango de fechas es requerido [InitialDate - EndDate].
	2- User, FieldKey, Operation, Entity, SubEntity son opcionales.
	- Si los filtros son solo por User y no Entidad, voy contra la CF "AuditByUser". En caso contrario voy contra "AuditByEntity"

	filters = {
		initialDate = "2022-03-01",
		endDate		= "2022-03-07",
		user		= "adminfull",
		operation	= "Update",
		fieldKey	= "callcamp",
		entity		= "Campaign",
		subEntity	= "subEntity"
	}
]]--
local function Filter (params)
	assert(params, "params are missing")
	assert(params.vcc, "params.vcc is required")
	assert(params.initialDate, "params.InitialDate is required")
	assert(params.endDate, "params.EndDate is required")
	assert(params.connection, "params.connection is required")

	local vcc        = params.vcc
	local admin      = params.user
	local operation  = params.operation
	local fieldKey   = params.fieldKey
	local entity     = params.entity
	local subEntity  = params.subEntity
	local connection = params.connection

	local startProcessTime = os.time()
	local initialDate = LuaOrm.Date(params.initialDate)
	local endDate = LuaOrm.Date(params.endDate)
	local rangeDays = (endDate:time() - initialDate:time()) /60 / 60 /24 -- segundos a dias
	LogInfo("[Audits::Filter] +START Executing filter function. Range Days: %s, startProcessTime: %s", rangeDays, startProcessTime)

	local MAX_ALLOWED_RANGE_DAYS = 31
	if rangeDays > MAX_ALLOWED_RANGE_DAYS then
		local reason = string.format("Audit rows cannot be filtered. A maximum range of %s days is allowed.", MAX_ALLOWED_RANGE_DAYS)
		LogError("[Audits::Filter] %s", reason)
		return false, {result = "AUDIT ROWS CANNOT BE FILTERED - A MAXIMUM RANGE OF DAYS IS ALLOWED", reason = reason, maxAllowedDays = MAX_ALLOWED_RANGE_DAYS}
	end

	local startSubProcessTime = startProcessTime
	local recordsfilters = m_model.GetRowsByDate({
		vcc         = vcc,
		initialDate = params.initialDate,
		endDate     = params.endDate,
		connection  = connection,
		order       = params.order
	})
	--LogDebug("[Audits::Filter]     a -> Time Executed function 'GetRowsByDate' elapsedTime %s seconds, endSubProcessTime: %s.", GetElapsedTimeSec(startSubProcessTime))

	if not next(recordsfilters) then
		LogInfo("[Audits::Filter] -END - NO RESULT FOUND Executed filter function. elapsedTime %s seconds, endSubProcessTime: %s.", GetElapsedTimeSec(startProcessTime))
		return true, {}
	end

	local filters = {
		admin        = admin,
		entity       = entity,
		operation    = operation,
		fieldKey     = fieldKey,
		vcc          = vcc,
		subEntity    = subEntity,
		paging       = params.paging,
		timeZoneInfo = params.timeZoneInfo,
		desc         = (params.order or "desc"):lower() and true or false
	}
	--LogDebug("%s", params.timeZoneInfo)
	startSubProcessTime = os.time()
	local filteredRecords, totalRecords, totalPageRecords = m_model.FilterRecords(filters, recordsfilters)
	--LogDebug("[Audits::Filter]     b -> Time Executed function 'FilterRecords' elapsedTime %s seconds, endSubProcessTime: %s.", GetElapsedTimeSec(startSubProcessTime))

--	LogDebug("[Audits::Filter] filteredRecords %s", m_json.encode(filteredRecords or {}))
	LogInfo("[Audits::Filter] -END Executed filter function. elapsedTime %s seconds, endProcessTime: %s", GetElapsedTimeSec(startProcessTime))
	return true, filteredRecords, totalRecords, totalPageRecords
end

--[[
	CleanUpPeriod - Espera de dias para limpiar bitacoras, por defecto 365
]]--
local function RemoveVccsAudits (params)
	assert(params, "params are missing")
	assert(params.vccs, "params.vccs is required")
	m_model.RemoveByDate({
		vccs = params.vccs
	})
end

---------------------------------------------------------------------------------
--
-- Exported functions
---------------------------------------------------------------------------------
return {
	init             = init,
	Create           = Create,
	Filter           = Filter,
	RemoveVccsAudits = RemoveVccsAudits,
	--[[
		API: agregada para solucionar el issue #13351 de performance.
			migracion de SuperCFs a CFs.
		
		Despues que el issue se haya validado esta API se puede eliminar.
	]]--
	MigrateRow = function (params)
		return model.NewRecord(params)
	end
}
