local m_cassandra
local m_redis
local m_authFilterAPI
local m_helpers = require "helpers"

module(..., package.seeall)

local m_cachedVCCInfo = {} -- se cachea la informacion necesaria, de momento solo el "override" de permisos.

function GetDatasource ()
	return m_cassandra, m_redis
end

function SetDatasource (cassandra, redis, authFilterAPI)
	--print("authfilter.SetDatasource")
	m_cassandra = cassandra
	m_redis = redis
	m_authFilterAPI = authFilterAPI
end

function GetTimezoneFromDB (timezoneId, keyspace)
	local release = false
	if not keyspace then
		keyspace = m_cassandra:CassandraConnection("Agent")
		release = true
	end
	local columns = keyspace:GetSliceRange(
		timezoneId,
		"Timezones",
		"",
		{
		--column_names = {},
			slice_range = {
				start = "",
				finish = "",
				reversed = true,
				count = 10
			}
		}
	)
	if release then
		keyspace:Close()
	end
	if not columns or not next(columns) then
		error( ("Timezone %q not found"):format(timezoneId) )
	end
	local row = {}
	for _, column in pairs(columns) do
		row[column.name] = column.value
	end
	local timezone = {
		id = timezoneId,								-- ej: "UYT",
		offset = tonumber(row.TimeZone),				-- ej: -3,
		minutes = tonumber(row.TimeZoneMinutes),		-- ej: 0,
		dst = (tonumber(row.DaylightSavingTime) ~= 0),	-- ej: true
		HistoricalDaylight = {}
	}

	local success, historicalDaylight = pcall(json.decode, row.HistoricalDaylight)
	if success then
		-- El historico es utilizado en la rocka "reporter", para determinar si una fecha determinada se encuentra dentro del horario de verano.
		timezone.HistoricalDaylight = historicalDaylight
-- 26/11/2020 desde las 0:00 a las 23:59
-- table.insert(timezone.HistoricalDaylight, {
--	EndDayLight = 1606435199,
--	StartDayLight = 1606348800,
--	isdst = true
--})

	end

	return timezone
end

--
-- Retrieves a user from the m_cassandra back-end
--
function GetUserFromCassandra (username, vcc, keyspace)
	local release = false
	if not keyspace then
		keyspace = m_cassandra:CassandraConnection("Agent")
		release = true
	end
	local userKey = username .. "@" .. vcc
	local columns = keyspace:GetSliceRange(
		userKey,
		"Users",
		"",
		{
			column_names = {},
			slice_range = {
				start = "",
				finish = "",
				reversed = true,
				count = 200
			}
		}
	)
	if release then
		keyspace:Close()
	end
	if not columns or not next(columns) then
		return nil, "user not found"
	end

	local user = {}
	for _, column in pairs(columns) do
		user[column.name] = column.value
	end

	local userdata = {
		id = userKey,
		username = username:lower(),
		virtualContactCenter = vcc:lower(),
		usergroup = user.UserGroup,
		groupVCC = user.VccGroup,
		languageId = user.LanguageId,
		codepage = "UTF-8",
		timezone = GetTimezoneFromDB(user.TimeZoneId or "UTC"),
		enabled = user.Enabled,
		fullname = user.Name,
		PasswordChangeTimestamp = user.PasswordChangeTimestamp,
		LoginFailedAttemps = user.LoginFailedAttemps,
		MustChangePassword = user.MustChangePassword,
		HasChangePasswordPermission = HasUserChangePasswordPermission(username:lower(), user.UserGroup, vcc),
		PasswordHistory = user.PasswordHistory and json.decode(user.PasswordHistory) or {},
		Status = user.Status,
		UserGroup = user.UserGroup:lower(),
		openIdUserId = user.openIdUserId,
		openIdUserGroup = user.openIdUserGroup,
		vccPermissions = m_cachedVCCInfo[vcc] and m_cachedVCCInfo[vcc].Permissions or {}
	}
	userdata.IsFullSystemAccess = m_authFilterAPI:IsUserFullSystemAccess(userdata)
	--LogDebug("[AUTHFILTER.MODEL:GetUserFromCassandra] **--> User '%s' userInfo: %s", userKey, json.encode(userdata))
	return userdata, user.Password
end

function GetUserByEmail (email, keyspace)
	local release = false
	if not keyspace then
		keyspace = m_cassandra:CassandraConnection("Agent")
		release = true
	end
	local columns = keyspace:GetSliceRange(
		email,
		"UsersByEmail",
		"",
		{
			column_names = {},
			slice_range = {
				start = "",
				finish = "",
				reversed = true,
				count = 200
			}
		}
	)
	if release then
		keyspace:Close()
	end
	if not columns or not next(columns) then
		return nil, "email not found"
	end

	local user = nil
	for _, column in pairs(columns) do
		if user then
			return nil, "email belongs to more than one user"
		end
		user = column.name
	end

	return user
end

function GetVCC (vcc, keyspace)
	local release = false
	if not keyspace then
		keyspace = m_cassandra:CassandraConnection("Agent")
		release = true
	end
	local columns = keyspace:GetSliceRange(vcc, "VCCs", "",
		{
			column_names = {},
			slice_range = {
				start = "",
				finish = "",
				reversed = true,
				count = 2000
			}
		}
	)
	if release then
		keyspace:Close()
	end
	if not columns or not next(columns) then
		error(("VCCs %q not found"):format(vcc))
	end
	local vccInfo = {}
	for _, column in pairs(columns) do
		-- El override de Permisos en el VCC se cachea en la VM ya que si este dato cambia, se debe reiniciar el webhandler y los usuarios deben volver a realizar loggin.
		if column.name == "Permissions" then
			local vccPermissions = json.decode(column.value)
			--LogDebug("[AUTHFILTER.MODEL:GetVCC] ---> vcc: %s -> %s: '%s'", vcc, column.name, json.encode(vccPermissions))
			m_cachedVCCInfo[vcc] = m_cachedVCCInfo[vcc] or {}
			m_cachedVCCInfo[vcc].Permissions = vccPermissions
			vccInfo[column.name] = vccPermissions
		else
			vccInfo[column.name] = column.value
		end
	end
	local options = {}
	if inconcert
		and inconcert.environment
		and inconcert.environment.apps
		and inconcert.environment.apps.agent
		and inconcert.environment.apps.agent.agentservice
		and inconcert.environment.apps.agent.cluster
	then
		options.host = inconcert.environment.apps.agent.agentservice.host
		options.port = inconcert.environment.apps.agent.agentservice.port
		options.cluster = inconcert.environment.apps.agent.cluster
	end
	return m_helpers.utils.HasLicenseSystem() and m_helpers.agentservice.GetVccWithLicenseInfo(options, vccInfo) or vccInfo
end

function HasUserChangePasswordPermission(username, usergroup, vcc, keyspace)
	local release = false
	if not keyspace then
		keyspace = m_cassandra:CassandraConnection("Agent")
		release = true
	end
	local userKey = username .. "@" .. vcc
	local groupKey = usergroup .. "@" .. vcc
	local groupSystemKey = usergroup .. "@" .. "system"

	local columns = keyspace:GetSliceRange(
		userKey,
		"UserPermission",
		"",
		{
			column_names = {},
			slice_range = {
				start = "",
				finish = "",
				reversed = true,
				count = 200
			}
		}
	)	
	for _, column in pairs(columns) do
		if column.name == "actions" then
			local userActions = json.decode(column.value)
			if userActions.settings and userActions.settings.change_personal_settings then
				-- user has change password permission.
				return true
			end
		end
	end	

	-- user hasnt change password permission.

	columns = keyspace:GetSliceRange(
		groupKey,
		"GroupPermission",
		"",
		{
			column_names = {},
			slice_range = {
				start = "",
				finish = "",
				reversed = true,
				count = 200
			}
		}
	)	
	for _, column in pairs(columns) do
		if column.name == "settings" then
			local groupSettings = json.decode(column.value)
			if groupSettings.change_personal_settings then
				-- group has change password permission
				return true
			end
		end
	end	

	-- group hasnt change password permission

	columns = keyspace:GetSliceRange(
		groupSystemKey,
		"GroupPermission",
		"",
		{
			column_names = {},
			slice_range = {
				start = "",
				finish = "",
				reversed = true,
				count = 200
			}
		}
	)	
	if release then
		keyspace:Close()
	end
	for _, column in pairs(columns) do
		if column.name == "settings" then
			local groupSettings = json.decode(column.value)
			if groupSettings.change_personal_settings then
				-- system group has change password permission
				return true
			end
		end
	end	

	-- system group hasnt change password permission
	return false
end
