local utf8            = require "icu.utf8"
local uuid            = require "uuid"
local m_helpers       = require "fullcontact.helpers"
local m_ormDate       = require "LuaOrm.Date"
local m_fullcontact  -- fullcontact module
local m_dialerAPI    -- Dialer All API Methods
local m_blackListAPI -- Blacklist All API Methods
local m_model        -- modelo de cassandra

--[[

]]--
local function LogFn (success)
	if success then
		return LogInfo
	end
	return LogError
end

-------------------------------------------------------
-- DIALER MIGRATIONS
-------------------------------------------------------

local m_migrations = {
	Allegro = {
		BlackList     = {},
		Contacts      = {},
		Imports       = {},
		ImportFormats = {}
	}
}
-- accesos directos (blacklist, contactos, importaciones, formatos de importacion)
local m_blackList     = m_migrations.Allegro.BlackList
local m_contacts      = m_migrations.Allegro.Contacts
local m_imports       = m_migrations.Allegro.Imports
local m_importFormats = m_migrations.Allegro.ImportFormats

--[[
]]--
m_migrations.Init = function(self, fullcontact)
	--LogDebug("[FULLCONTACT.Migration:Init] Initializing module ............. fullcontact: %s", fullcontact)
	m_fullcontact  = fullcontact
	m_dialerAPI    = m_fullcontact.Dialer:GetDialerApi()
	m_blackListAPI = m_fullcontact.Dialer:GetBlackListApi()
	m_model        = m_fullcontact:GetModel()
end

-------------------------------------------------------
-- ALLEGRO - CONTACTS
-------------------------------------------------------

--[[
]]--
m_contacts.Migrate = function (self, vcc, allegroContacts, ksOE, ksAgent)
	assert(type(vcc) == "string")
	assert(type(allegroContacts) == "table")
	-- 1  (en memoria) creo los contactos con el formato Nativo a partir del formato de Allegro
	--
	--LogInfo("[FULLCONTACT.Migration:Migrate]  1 -Migrating allegroContacts of VCC '%s'. total allegroContacts-> %s.", vcc, #allegroContacts)
	local nativeContacts, contactsByBatches, blackList, errors = m_contacts:MakeNativeContacts(vcc, allegroContacts)
	if #errors == #allegroContacts then
		LogError("[FULLCONTACT:Migrate] Unable to migrate all Allegro contacts. total %s.", #allegroContacts)
		return false, {err = "UNABLE TO MIGRATE ALL ALLEGRO CONTACTS", errors = errors}
	end
	-- start migration
	-- 2  (ES) comienza el proceso de migracion de los contactos, finalizando el almacenamiento en ES.
	--
	local success, migrationResult = m_model.Dialer:MigrateContactsBatch(vcc, nativeContacts)
	-- LogDebug("[FULLCONTACT.Migration:Migrate] 5 - Result of Migration contacts of VCC '%s'. success: %s, migrationResult: %s.", vcc, success, json.encode(migrationResult))
	if not success then
		local err = migrationResult
		LogError("[FULLCONTACT:Migrate] Unable to migrate Allegro contacts. err %s.", json.encode(err))
		return false, {err = "UNABLE TO MIGRATE ALLEGRO CONTACTS", errors = err}
	end
	-- blacklist
	-- 3 comienza la creacion de la blacklist.
	m_blackList:Migrate(vcc, blackList, ksOE, ksAgent)
	-- ok
	--LogDebug("[FULLCONTACT.Migration:Migrate] 6 ---> Result of Migration contacts of VCC '%s'. isOK, contactsByBatches: %s.", vcc, json.encode(contactsByBatches))
	return true, contactsByBatches
end

--[[
	Lo que realiza es eliminar el indice del vcc y volver a vacio.
	Tambien realiza rollback de las blacklist.
]]--
m_contacts.Rollback = function (self, vcc, ksOE, ksAgent)
	assert(type(vcc) == "string")
	LogDebug("")
	LogDebug("----------------------------------------------------------------")
	LogInfo("[FULLCONTACT.Migration:Rollback]  1 -Rollbacking allegroContacts for VCC '%s'.", vcc)
	-- 1 - DROP ES INDEX
	LogInfo("[FULLCONTACT.Migration:Rollback]    1.1 - Wait moment --> DropESIndex for VCC '%s'.", vcc)
	local success, response = m_dialerAPI:DropESIndex(vcc)
	LogFn(success)("      DROP ES INDEX result ---> success '%s', response '%s'.", success, json.encode(response))
	LogDebug("")
	--require("socket").sleep(3) -- Pequena pausa necesaria.
	-- 2 - CREATE TEMPLATE
	LogInfo("[FULLCONTACT.Migration:Rollback]    1.2 - Wait moment --> CreateESTemplate for VCC '%s'.", vcc)
	local success, response = m_dialerAPI:CreateESTemplate()
	LogFn(success)("      CREATE TEMPLATE result ---> success '%s', response '%s'.", success, json.encode(response))
	LogDebug("")
	--require("socket").sleep(3) -- Pequena pausa necesaria.
	-- 3 - CREATE ES INDEX
	LogInfo("[FULLCONTACT.Migration:Rollback]    1.3 - Wait moment --> CreateESIndex for VCC '%s'.", vcc)
	local success, response = m_dialerAPI:CreateESIndex(vcc)
	LogFn(success)("      CREATE ES INDEX result ---> success '%s', response '%s'.", success, json.encode(response))
	-- blacklist
	-- 4 comienza la creacion de la blacklist.
	LogInfo("[FULLCONTACT.Migration:Rollback]    1.4 - Wait moment --> Rollback Allegro blacklist VCC '%s'.", vcc)
	m_blackList:Rollback(vcc, ksOE, ksAgent)
	LogDebug("")
	LogDebug("----------------------------------------------------------------")
	LogDebug("")
	return true
end

--[[
]]--
m_contacts.MakeNativeContacts = function (self, vcc, allegroContacts)
	assert(type(vcc) == "string")
	assert(type(allegroContacts) == "table")
	--LogDebug("[FULLCONTACT.Migration:MakeNativeContacts]  Making Native Contacts from Allegro for VCC '%s'. allegroContacts: %s", vcc, json.encode(allegroContacts))
	local errors = {}
	local nativeContacts = {}
	local contactsByBatches = {}
	local blackList = {}
	for _, allegroContact in ipairs(allegroContacts) do
		local success, nativeContact, allegroBatch, invalidAddresses, phonesInBlacklist = m_contacts:MakeNativeContact(vcc, allegroContact)
		if success then
			table.insert(nativeContacts, nativeContact)
			if allegroBatch then
				local totalIvalidAddresses = #(invalidAddresses or {})
				if totalIvalidAddresses == 0 then
					-- (no es un vcc) pero se usa esta funcion de helpers ya que el id esta conformado por procesoId@batchId
					local processBatchId = m_helpers.AddVCC(allegroBatch.OutboundProcessId, allegroBatch.BatchId):lower()
					contactsByBatches[processBatchId] = contactsByBatches[processBatchId] or {
						ProcessId        = allegroBatch.OutboundProcessId:lower(),
						BatchId          = allegroBatch.BatchId:lower(),
						BatchPriority    = allegroBatch.BatchPriority,
						ContactPriority  = allegroBatch.ContactPriority,
						--[[
							 lista de todos los contactos que se asignaran al lote cuando sea crea el mismo mediante el metodo "CreateBatch" del API del OEClient en la App "outboundengine".
						]]--
						Contacts         = {},
						--[[
							lista de contactos por estados "state" (CANCELED, PAUSED, CONTACTED/FINIHSED)
								con estas listas se ejecutaran los metodos respectivos del API del OEClient para que cambie el estado de los mismos.
								(CancelContacts, PauseContacts, FinishContacts)
						]]--
						ContactsByStates = {}
					}
					--  Tambien puede llegar como NULL este campo entonces dejo el string NULL
					local contactState = (allegroBatch.Status or "NULL"):upper()
					if contactState == "CONTACTED" then
						-- realizo esta pisada ya que, el estado CONTACTED como tal en el OE Nativo NO existe y se interpreta como FINISHED
						contactState = "FINISHED"
					end
					-- CreateBatch/AddContacts (al batch): agrego en la lista para la creacion de los batches
					local contactId = nativeContact.Id:lower()
					if not contactsByBatches[processBatchId].Contacts[contactId] then
						local contact = {
							id           = contactId, -- en este formato lo espera el OE cuando se va crear y ejecutar el proceso/batch.
							agent        = #(allegroBatch.ReservedActor or "") > 0 and allegroBatch.ReservedActor:lower() or nil,
							state        = contactState,
							stateCause   = allegroBatch.Cause
						}
						-- si esta SCHEDULED debo proporcionar la fecha de agendado, y la obtengo primero desde ManualScheduledDate y si viene en NULL la debo obtener desde ScheduledDate
						--  en el caso en que vengan ambas fechas y la ScheduledDate sea mayor a la fecha ManualScheduledDate, me tengo que quedar con la fecha ScheduledDate
						if contactState == "SCHEDULED" then
							local manualScheduledDate = allegroBatch.ManualScheduledDate
							local scheduledDate = allegroBatch.ScheduledDate
							if manualScheduledDate and scheduledDate then
								if m_ormDate(scheduledDate):time() > m_ormDate(manualScheduledDate):time() then
									contact.scheduleDate = scheduledDate
								else
									contact.scheduleDate = manualScheduledDate
								end
							else
								contact.scheduleDate = manualScheduledDate or scheduledDate
							end
						end
						contactsByBatches[processBatchId].Contacts[contactId] = contact
					end
					-- CancelContacts, PauseContacts, FinishContacts: agrego en la lista para cambiar los estados de los contactos / batches
					contactsByBatches[processBatchId].ContactsByStates[contactState] = contactsByBatches[processBatchId].ContactsByStates[contactState] or {Contacts={}}
					contactsByBatches[processBatchId].ContactsByStates[contactState].Contacts[contactId] = {
						id         = contactId, -- en este formato lo espera el OE cuando se va a cambiar el estado de los batches/contactos
						state      = allegroBatch.Status,
						stateCause = allegroBatch.Cause
					}
				else
					LogWarning("[FULLCONTACT.Migration:MakeNativeContacts] ---> Unable to add contact '%s' to batch '%s' of process '%s'. The contact has %s invalid addresses.", nativeContact.Id, allegroBatch.BatchId, allegroBatch.BatchId, totalIvalidAddresses)
				end
			end
			-- blacklist
			for _, phone in ipairs(phonesInBlacklist or {}) do
				table.insert(blackList, phone)
			end
		else
			local err = nativeContact
			table.insert(errors, err)
		end
	end
	--ok
	return nativeContacts, contactsByBatches, blackList, errors
end

--[[
param allegroContact
{
	"AccountGroup": "",
	"VCC": 120,
	"AccountOfficer": "",
	"VIP": 0,
	"Campaign": "",
	"Category": "",
	"ID": "00EFA2DA0CAB4FB7A3F8FD3B128F6C18",
	"Name": "Nombre_4",
	"IsClient": 0,
	"LastUpdate": "ImprtationID",
	"Phones": [
		{
		"Number": "27000000",
		"Type": "HOME",
		"Extension": "",
		"Country": 598,
		"DisplayStatus": "Enabled",
		"DisplayType": "Home",
		"ImportName": "Telefono",
		"Zip": -1,
		"ContactID": "00EFA2DA0CAB4FB7A3F8FD3B128F6C18",
		"Status": "ENABLED",
		"ContactVCC": 120,
		"Area": 1
		}
	],
	"Batches": [
		{
		"TimeZoneScheduledDate": "",
		"Status": "PAUSED",
		"DisplayCause": "",
		"VCC": "emmatel2",
		"TimeZonePreviousContactDate": "",
		"BatchId": "LoTeUnO",
		"DisplayStatus": "Paused",
		"ImportId": "ImprtationID",
		"OutboundProcessId": "process1",
		"ContactPriority": 100,
		"InProcess": 0,
		"ContactId": "00EFA2DA0CAB4FB7A3F8FD3B128F6C18",
		"ReservedActor": "",
		"VCCNumId": 120,
		"BatchPriority": 1,
		"DisplayNextDestination": ""
		}
	],
},

return nativeContact
{
  "AccountGroup": "",
  "NameValuesSearchText": [],
  "LastUpdate": "2023-03-20 12:30:45.000",
  "NameValuesSearchNumeric": [],
  "ImportId": "borrame1",
  "NameValuesSearchDate": [],
  "Category": "",
  "Addresses": [
    {
      "Number": "+59824000003",
      "Type": "Phone",
      "Extension": "",
      "Channels": [
        "CALL"
      ],
      "Area": "",
      "SameCountry": "24000003",
      "SanitizedId": "+59824000003",
      "ZipPhone": "",
      "LocalNumber": "24000003",
      "Validation": {
        "Success": true
      },
      "SimpleNumber": "24000003",
      "displayable": "+59824000003",
      "Status": "Enabled",
      "Kind": "HOME",
      "Country": "598",
      "AccountId": "PHONE_598__24000003_"
    }
  ],
  "HomeAddresses": [],
  "CreatedAt": "2023-03-20 12:30:45.000",
  "IsClient": false,
  "LastImportName": "",
  "State": "FREE",
  "ExternalId": "",
  "AccountOfficer": "",
  "Campaign": "",
  "Skills": [],
  "NameValuesSimple": [],
  "Name": "el nombre",
  "Id": "el id@vcc",
  "VCC": "vcc"
}
]]--
m_contacts.MakeNativeContact = function (self, vcc, allegroContact)
	assert(type(vcc) == "string")
	assert(type(allegroContact) == "table")
	--LogDebug("[FULLCONTACT.Migration:MakeNativeContact]  1 -Making Native Contact from Allegro Contact for VCC '%s'. allegroContact: %s", vcc, json.encode(allegroContact))
	local importInfo = {
		ID               = allegroContact.LastUpdate or "",
		VCC              = vcc,
		AreClientsImport = tostring(allegroContact.IsClient) == "1"
	}
	local nameValuesInfo = m_contacts:MakeNameValuesFromAllegro(vcc, allegroContact)
	local contactData = {
		ID                      = m_helpers.AddVCC(allegroContact.ID, vcc):lower(),
		NAME                    = allegroContact.Name or "",
		ACCOUNTGROUP            = allegroContact.AccountGroup or "",
		ACCOUNTOFFICER          = allegroContact.AccountOfficer or "",
		addresses               = m_contacts:MakeAddressesFromAllegro(vcc, allegroContact), -- PHONE, EMAIL, etc
		CAMPAIGN                = allegroContact.Campaign or "",
		CATEGORY                = allegroContact.Category or "",
		EXTERNALID              = nil,
		homeAddresses           = nil,
		LastImportName          = allegroContact.LastUpdate or "",
		nameValuesSimple        = nameValuesInfo.Simple,
		nameValuesSearchDate    = nameValuesInfo.SearchDate,
		nameValuesSearchNumeric = nameValuesInfo.SearchNumeric,
		nameValuesSearchText    = nameValuesInfo.SearchText,
		scheduledCall           = m_contacts:MakeScheduledCallFromAllegro(vcc, allegroContact),
		skills                  = m_contacts:MakeSkillsFromAllegro(vcc, allegroContact)
	}
	--
	--LogDebug("[FULLCONTACT.Migration:MakeNativeContact]  2 -Maked Native Contact from Allegro Contact for VCC '%s'. Result -> contactData: %s", vcc, json.encode(contactData))
	local migrationInfo = {Type = "ALLEGRO", SourceContact = allegroContact, skipValidatePhone = true}
	local nativeContact, addresses, invalidAddresses = m_dialerAPI:MakeContactInfo(contactData, importInfo, migrationInfo)
	--LogDebug("[FULLCONTACT.Migration:MakeNativeContact]  3 -Maked Native Contact from Allegro Contact for VCC '%s'. Result -> nativeContact: %s", vcc, json.encode(nativeContact))
	--LogDebug("[FULLCONTACT.Migration:MakeNativeContact]  4 -Maked Native Contact from Allegro Contact for VCC '%s'. Result -> addresses: %s", vcc, json.encode(addresses))
	--LogDebug("[FULLCONTACT.Migration:MakeNativeContact]  5 -Maked Native Contact from Allegro Contact for VCC '%s'. Result -> invalidAddresses: %s", vcc, json.encode(invalidAddresses))
	--
	local allegroBatch = m_contacts:GetLastContactBatchByAllegro(allegroContact.Batches)
	--
	local _, phonesInBlacklist = m_blackList:MakeContactBlackList(vcc, allegroContact, addresses)
	--ok
	return true, nativeContact, allegroBatch, invalidAddresses, phonesInBlacklist
end

--[[
Recive
	 {
		{
			ContactID = contactId,
			Number = "27000000",
			Type = "HOME",
			Extension = "",
			Country = 598,
			DisplayStatus = "Enabled",
			DisplayType = "Home",
			ImportName = "Telefono",
			Zip = -1,
			Status = "ENABLED",
			ContactVCC = 120,
			Area = 1
		},
		..
	}

Retorna

]]--
m_contacts.MakePhoneAddressesFromAllegro = function (self, vcc, allegroPhones)
	assert(type(vcc) == "string")
	if type(allegroPhones) ~= "table" then
		return {}
	end
	--LogDebug("[FULLCONTACT.Migration:MakePhoneAddressesFromAllegro]  1 -Making PHONE addresses from allegro for VCC '%s'. allegroPhones: %s", vcc, json.encode(allegroPhones))

	--[[
		Sanitiza las areas segun el country.
		En el caso de Uruguay (country 598) desde el Allegro el area llega con un valor ya que la tabla no permite valores nulos.
		Pero el valor correcto en este caso debe de ser "".
	]]--
	local function SanitizeArea (country, area)
		area = tonumber(area)
		if type(area) ~= "number" then
			return ""
		end
		country = tostring(country)
		local sanitizedAreasByCounties = {
			["598"] = {area = ""}
		}
		local config = sanitizedAreasByCounties[country]
		if config then
			return config.area
		end
		-- espera un string
		return tostring(area)
	end

	--[[
		Sanitiza los ZipPhone si llegan valores negativos los convierte a "" (string vacio)
	]]--
	local function SanitizeZip (zip)
		zip = tonumber(zip)
		if type(area) ~= "number" or zip < 0 then
			return ""
		end
		-- espera un string
		return tostring(zip)
	end

	local addresses = {}
	for _, allegroPhone in ipairs(allegroPhones) do
		local allegroStatus = (allegroPhone.Status or "ENABLED"):upper()
		-- datos del numero de telefono
		local country = allegroPhone.Country
		local area = SanitizeArea(allegroPhone.Country, allegroPhone.Area)
		local number = allegroPhone.Number or ""
		local isGlobalNumber = m_dialerAPI:IsGlobalPhone(number, country, area)
		local fullPhoneNumber = isGlobalNumber
			and number
			or string.format("%s%s%s", country, area, allegroPhone.Number or "")
		--LogDebug("[FULLCONTACT.Migration:MakePhoneAddressesFromAllegro]  --> isGlobalNumber: %s fullPhoneNumber %s", isGlobalNumber, fullPhoneNumber)
		--
		-- el address
		local address = {
			type      = "phone",
			Number    = fullPhoneNumber, --allegroPhone.Number,
			DialLocal = number,
			Country   = country,
			Area      = area,
			Kind      = (allegroPhone.Type or "PHONE"):upper(),
			Extension = allegroPhone.Extension,
			ZipPhone  = SanitizeZip(allegroPhone.Zip),
			Status    = allegroStatus == "ENABLED" and "Enabled" or "Disabled"
		}
		table.insert(addresses, address)
	end
	--LogDebug("[FULLCONTACT.Migration:MakePhoneAddressesFromAllegro]  2 -Maked PHONE addresses from allegro for VCC '%s'. addresses: %s", vcc, json.encode(addresses))
	--ok
	return addresses
end

--[[
Recive
	 {
		{
			Address = "correo@mail.com",
			Type = "PERSONAL", -- WORK
			Status = "ENABLED", -- DISABLED
		},
		..
	}

Retorna
		SanitizedId = SanitizeId(address.address, "MAIL"),
		Type = "Mail",
		Kind = address.Kind or address.addressSubType or "", -- (WORK, PERSONAL)
		address = assert(address.address),
		displayable = assert(address.address),
		Status = address.Status or "Enabled",
		Channels = MakeChannels(address.Channels or defaultChannels),
		-- TODO: Realizar validacion ? Si no se realiza la validacion, la estructura Validation tiene que viajar igual
		Validation = {
			Success = true,
			Error   = nil
		}
]]--
m_contacts.MakeEmailAddressesFromAllegro = function (self, vcc, allegroEmails)
	assert(type(vcc) == "string")
	if type(allegroEmails) ~= "table" then
		return {}
	end
	--LogDebug("[FULLCONTACT.Migration:MakeEmailAddressesFromAllegro]  1 -Making EMAIL addresses from allegro for VCC '%s'. allegroEmails: %s", vcc, json.encode(allegroEmails))
	--[[
	]]--
	local addresses = {}
	for _, allegroEMail in ipairs(allegroEmails) do
		local allegroStatus = (allegroEMail.Status or "ENABLED"):upper()
		-- el address
		local address = {
			type           = "mail",
			address        = allegroEMail.Address,
			addressSubType = allegroEMail.Type,
			Status         = allegroStatus == "ENABLED" and "Enabled" or "Disabled"
		}
		table.insert(addresses, address)
	end
	--LogDebug("[FULLCONTACT.Migration:MakeEmailAddressesFromAllegro]  2 -Maked EMAIL addresses from allegro for VCC '%s'. addresses: %s", vcc, json.encode(addresses))
	--ok
	return addresses
end

--[[

]]--
m_contacts.MakeAddressesFromAllegro = function (self, vcc, allegroContact)
	assert(type(vcc) == "string")
	assert(type(allegroContact) == "table")
	--LogDebug("[FULLCONTACT.Migration:MakeAddressesFromAllegro]  1 -Making NATIVE addresses from allegro for VCC '%s'.", vcc)
	local addresses = {}
	local function JoinAddresses (addressList)
		--LogDebug("[FULLCONTACT.Migration:MakeAddressesFromAllegro]     -[JoinAddresses] addressList '%s'.", json.encode(addressList))
		for i, address in ipairs(addressList) do
			--LogDebug("[FULLCONTACT.Migration:MakeAddressesFromAllegro]       %d -> insert-[JoinAddresses] address '%s'.", i, json.encode(address))
			table.insert(addresses, address)
		end
	end
	-- telefonos
	local phoneAddresses = m_contacts:MakePhoneAddressesFromAllegro(vcc, allegroContact.Phones)
	JoinAddresses(phoneAddresses)
	-- emails
	local emailAddresses = m_contacts:MakeEmailAddressesFromAllegro(vcc, allegroContact.EMails)
	JoinAddresses(emailAddresses)
	--LogDebug("[FULLCONTACT.Migration:MakeAddressesFromAllegro]  2 -Maked NATIVE addresses from allegro for VCC '%s'. ALL Addresses: %s", vcc, json.encode(addresses))
	--ok
	return addresses
end

--[[

]]--
m_contacts.MakeNameValuesFromAllegro = function (self, vcc, allegroContact)
	assert(type(vcc) == "string")
	assert(type(allegroContact) == "table")
	--LogDebug("[FULLCONTACT.Migration:MakeNameValuesFromAllegro]  1 -Making NameValues from allegro for VCC '%s' contactId: %s. NameValues: %s", vcc, allegroContact.ID, allegroContact.NameValues)
	local allNativesNameValues = {
		Simple        = nil,
		SearchDate    = nil,
		SearchNumeric = nil,
		SearchText    = nil
	}
	-- obtengo la definicion con los topes maximos permitidos por namevalues searcheables (DATE, NUMERIC, TEXT).
	local nameValuesSearchByType = m_dialerAPI.GetAllowedNameValuesSearchByType(true)
	-- relizo la asignacion
	for i, allegroNameValue in ipairs(allegroContact.NameValues or {}) do
		local nativeNameValue = {
			name  = utf8.lower(m_helpers.alltrim(allegroNameValue.Name)),
			value = allegroNameValue.Value
		}
		local mustAddInSimpleNameValues = false
		local dataType = (allegroNameValue.Datatype or "STRING"):upper()
		local dataTypeAddedInfo = nameValuesSearchByType[dataType]
		if not dataTypeAddedInfo or (dataTypeAddedInfo.total + 1) > dataTypeAddedInfo.maxAllowed then
			mustAddInSimpleNameValues = true
			if not dataTypeAddedInfo then
				LogDebug("[FULLCONTACT.Migration:MakeNameValuesFromAllegro]        %d - Unrecognized NamveValue Type '%s' -> nativeNameValue: %s. Will be added in the SIMPLE NameValue list. Contact: %s.",
					i, dataType:upper(), json.encode(nativeNameValue), allegroContact.ID)
			else
				LogDebug("[FULLCONTACT.Migration:MakeNameValuesFromAllegro]        %d - You have reached the maximum of %d namedvalues supported for the type '%s'. It will be added in the simple list. nativeNameValue: %s. Contact: %s.",
					i, dataTypeAddedInfo.total, dataType:upper(), json.encode(nativeNameValue), allegroContact.ID)
			end
		else
			dataTypeAddedInfo.total = dataTypeAddedInfo.total + 1
			if dataType == "STRING" then
				allNativesNameValues.SearchText = allNativesNameValues.SearchText or {}
				table.insert(allNativesNameValues.SearchText, nativeNameValue)
				--LogDebug("[FULLCONTACT.Migration:MakeNameValuesFromAllegro]        %d - Adding STRING NameValue -> nativeNameValue: %s", i, json.encode(nativeNameValue))
			elseif dataType == "NUMBER" then
				allNativesNameValues.SearchNumeric = allNativesNameValues.SearchNumeric or {}
				table.insert(allNativesNameValues.SearchNumeric, nativeNameValue)
				--LogDebug("[FULLCONTACT.Migration:MakeNameValuesFromAllegro]        %d - Adding NUMERIC NameValue -> nativeNameValue: %s", i, json.encode(nativeNameValue))
			elseif dataType == "DATE" then
				allNativesNameValues.SearchDate = allNativesNameValues.SearchDate or {}
				table.insert(allNativesNameValues.SearchDate, nativeNameValue)
				--LogDebug("[FULLCONTACT.Migration:MakeNameValuesFromAllegro]        %d - Adding DATE NameValue -> nativeNameValue: %s", i, json.encode(nativeNameValue))
			end
		end
		--
		if mustAddInSimpleNameValues then
			allNativesNameValues.Simple = allNativesNameValues.Simple or {}
			table.insert(allNativesNameValues.Simple, nativeNameValue)
			--LogDebug("[FULLCONTACT.Migration:MakeNameValuesFromAllegro]        %d - Adding SIMPLE NameValue -> nativeNameValue: %s", i, json.encode(nativeNameValue))
		end
	end
	--LogDebug("[FULLCONTACT.Migration:MakeNameValuesFromAllegro]  2 -Maked NATIVE NameValues from allegro for VCC '%s'. nativeNameValue: %s", vcc, json.encode(allNativesNameValues))
	--ok
	return allNativesNameValues
end

--[[

]]--
m_contacts.MakeSkillsFromAllegro = function (self, vcc, allegroContact)
	assert(type(vcc) == "string")
	assert(type(allegroContact) == "table")
	--LogDebug("[FULLCONTACT.Migration:MakeSkillsFromAllegro]  1 -Making Skills from allegro for VCC '%s'. Skills: %s", vcc, allegroContact.Skills)
	local nativeSkills = nil
	for i, allegroSkill in ipairs(allegroContact.Skills or {}) do
		nativeSkills = nativeSkills or {}
		local nativeSkill = {
			Mode          = "REQUIRED", -- PREFERRED
			SkillId       = allegroSkill.SkillID,
			SkillReqValue = allegroSkill.RequiredToLoad,
			value         = allegroSkill.Value
		}
		table.insert(nativeSkills, nativeSkill)
	end
	--LogDebug("[FULLCONTACT.Migration:MakeSkillsFromAllegro]  2 -Maked NATIVE Skills from allegro for VCC '%s'. Skills: %s", vcc, json.encode(nativeSkills or {}))
	--ok
	return nativeSkills
end

--[[

]]--
m_contacts.MakeScheduledCallFromAllegro = function (self, vcc, allegroContact)
	assert(type(vcc) == "string")
	assert(type(allegroContact) == "table")
	--LogDebug("[FULLCONTACT.Migration:MakeScheduledCallFromAllegro]  1 -Making ScheduledCall from allegro for VCC '%s'. ScheduledCalls: %s", vcc, allegroContact.ScheduledCalls)
	local allegroScheduledCall = (allegroContact.ScheduledCalls or {})[1]
	local nativeScheduledCall = allegroScheduledCall and allegroScheduledCall.CallDate or nil
	--LogDebug("[FULLCONTACT.Migration:MakeScheduledCallFromAllegro]  2 -Maked NATIVE ScheduledCall from allegro for VCC '%s'. nativeScheduledCall: %s", vcc, nativeScheduledCall)
	--ok
	return nativeScheduledCall
end

--[[
	obtengo el ultimo de los batches ya que en Nativo el contacto solo puede tener un Batch asociado.
]]--
m_contacts.GetLastContactBatchByAllegro = function (self, allegroBatches)
	allegroBatches = allegroBatches or {}
	local allegroBatch = allegroBatches[#allegroBatches]
	if not allegroBatch then
		return
	end
	--LogDebug("[FULLCONTACT.Migration:GetLastContactBatchByAllegro] allegroBatch: %s", json.encode(allegroBatch or {}))
	return allegroBatch
end

-------------------------------------------------------
-- ALLEGRO - IMPORTS
-------------------------------------------------------

--[[
]]--
m_imports.Migrate = function (self, vcc, allegroImports, ksOE)
	assert(type(vcc) == "string")
	assert(type(allegroImports) == "table")
	LogInfo("[FULLCONTACT.Migration.Imports:Migrate]  1 -Migrating allegroImports of VCC '%s'. allegroImports-> %s.", vcc, #allegroImports)
	--LogDebug("[FULLCONTACT.Migration.Imports:Migrate]  2 -Migrating allegroImports of VCC '%s'. allegroImports-> %s.", vcc, json.encode(allegroImports))
	-- 1 -- realiza el mapeo de informacion de importaciones de allegro a nativos
	local nativeImports, errors = m_imports:MakeNativeImports(vcc, allegroImports)
	--LogDebug("[FULLCONTACT.Migration.Imports:Migrate] 3 - Migrating imports of VCC '%s'. nativeImports-> %s.", vcc, json.encode(nativeImports))
	--LogDebug("[FULLCONTACT.Migration.Imports:Migrate] 4 - Migrating imports of VCC '%s'. errors-> %s.", vcc, json.encode(errors))
	if #errors == #allegroImports then
		LogError("[FULLCONTACT.Migration.Imports:Migrate] Unable to migrate all Allegro Imports. total %s.", #allegroImports)
		return false, {err = "UNABLE TO MIGRATE ALL ALLEGRO IMPORTS", errors = errors}
	end
	-- start migration
	-- 2  comienza el proceso de migracion de los importaciones
	--
	for _, nativeImport in ipairs(nativeImports) do
		local importId = m_helpers.AddVCC(nativeImport.ID, vcc):lower()
		local success = m_model.Dialer.SaveContactImportInDB(importId, nativeImport, ksOE)
		if not success then
			local err = {err = "UNABLE TO MIGRATE ALLEGRO IMPORT", importId = importId}
			table.insert(errors, err)
		end
	end
	-- ok
	LogDebug("[FULLCONTACT.Migration.Imports:Migrate] 5 ---> Result of Migration Imports of VCC '%s'. isOK.", vcc)
	return true
end

--[[
]]--
m_imports.Rollback = function (self, vcc, ksOE)
	assert(type(vcc) == "string")
	LogInfo("[FULLCONTACT.Migration.Imports:Rollback]  1 -Rollbacking Native Imports of VCC '%s' to Allegro Imports.", vcc)
	local success, nativeImports = m_model.Dialer.ListImportations({vcc = vcc}, ksOE)
	if not success then
		local err = {err = "UNABLE TO ROLLBACK NATIVE IMPORTS TO ALLEGRO - NO IMPORTATIONS LIST FOR VCC", vcc = vcc}
		LogError("[FULLCONTACT.Migration.Imports:Rollback] Unable to Rollback Native Imports. Err: %s.", json.encode(err))
		return false, err
	end
	for _, nativeImport in ipairs(nativeImports or {}) do
		local importIdWithVCC = m_helpers.AddVCC(nativeImport.ID, vcc):lower()
		m_model.Dialer.RemoveContactImportFromDB(importIdWithVCC, ksOE)
	end
	-- ok
	return true
end

--[[
]]--
m_imports.MakeNativeImports = function (self, vcc, allegroImports)
	assert(type(vcc) == "string")
	assert(type(allegroImports) == "table")
	--LogDebug("[FULLCONTACT.Migration.Imports:MakeNativeImports]  Making Native Imports from Allegro for VCC '%s'. allegroImports: %s", vcc, json.encode(allegroImports))
	local errors = {}
	local nativeImports = {}
	for _, allegroImport in ipairs(allegroImports) do
		local success, nativeImport = m_imports:MakeNativeImport(vcc, allegroImport)
		if success then
			table.insert(nativeImports, nativeImport)
		else
			local err = nativeContact
			table.insert(errors, err)
		end
	end
	--ok
	return nativeImports, errors
end

--[[
]]--
m_imports.MakeNativeImport = function (self, vcc, allegroImport)
	assert(type(vcc) == "string")
	assert(type(allegroImport) == "table")
	--LogDebug("[FULLCONTACT.Migration.Imports:MakeNativeImport]  1 -Making Native Import from Allegro Import for VCC '%s'. allegroImport: %s", vcc, json.encode(allegroImport))

	-- 1- la importacion
	local nativeImport = {
		-- SI - valores que llegan desde allegro
		ID                   = utf8.lower(allegroImport.ID),
		VCC                  = vcc,
		DBProvider           = allegroImport.DBProvider or "",
		Updates              = allegroImport.Updates or 1,
		-- NO - valores que no llegan desde allegro
		FormatId             = allegroImport.Name or "",
		CreationDate         = os.time(),
		LastModificationDate = os.time(),
		UserId               = "migrator@system",
		-- Diferentes - a crear ya que los valores llegan diferentes desde allegro
		Status               = {
			status = allegroImport.Status or "COMPLETE",
			-- valores que llegan y agregamos valores por defecto
			action  = "ENDING",
			updated = 0,
			total   = 0,
			errors  = 0,
			added   = 0,
			deleted = 0
		},
		Detail = {},
		-- Allegro - existen en Allegro pero no mapean en Nativo
		Allegro = {
			ServiceId = allegroImport.ServiceId
		}
	}
	-- 2 - el detalle de la importacion
	for _, allegroDetail in ipairs(allegroImport.ContactImportDetails or {}) do
		local nativeDetail = {
			-- SI - valores que llegan desde allegro
			ImportId   = allegroDetail.ImportId,
			VCC        = vcc,
			UserId     = allegroDetail.ImportUser,
			StartDate  = allegroDetail.Date,
			Status     = allegroDetail.Result or "COMPLETE",
			Added      = allegroDetail.NewContacts or 0,
			Errors     = allegroDetail.InvalidContacts or 0,
			Updated    = allegroDetail.UpdatedContacts or 0,
			-- NO - valores que no llegan desde allegro
			Deleted    = 0,
			FormatId   = "NONE",
			DetailId   = uuid.new(),
			UpdateDate = allegroDetail.Date,
			-- Diferentes - a crear ya que los valores llegan diferentes desde allegro
			-- ...
			-- Allegro - existen en Allegro pero no mapean en Nativo
			Allegro = {
				["Update#"]                  = allegroDetail["Update#"],
				AvailableInvalidContactsFile = allegroDetail.AvailableInvalidContactsFile,
				TimeZoneDate                 = allegroDetail.TimeZoneDate,
				ValidContacts                = allegroDetail.ValidContacts
			}
		}
		nativeDetail.Total = nativeDetail.Added + nativeDetail.Updated
		table.insert(nativeImport.Detail, nativeDetail)
	end

	--LogDebug("[FULLCONTACT.Migration.Imports:MakeNativeImport]  2 -Maked Native Import from Allegro Import for VCC '%s'. Result -> nativeImport: %s", vcc, json.encode(nativeImport))
	--LogDebug("[FULLCONTACT.Migration.Imports:MakeNativeImport]  3 -Maked Native Import from Allegro Import for VCC '%s'. Result -> invalidAddresses: %s", vcc, json.encode(invalidAddresses))

	--
	return true, nativeImport
end

-------------------------------------------------------
-- ALLEGRO - IMPORT FORMATS
-------------------------------------------------------

--[[
]]--
m_importFormats.Migrate = function (self, vcc, allegroImportFormats, ksOE)
	assert(type(vcc) == "string")
	assert(type(allegroImportFormats) == "table")
	LogInfo("[FULLCONTACT.Migration.ImportFormats:Migrate]  1 -Migrating allegroImportFormats of VCC '%s'. allegroImportFormats-> %s.", vcc, #allegroImportFormats)
	--LogDebug("[FULLCONTACT.Migration.ImportFormats:Migrate]  2 -Migrating allegroImportFormats of VCC '%s'. allegroImportFormats-> %s.", vcc, json.encode(allegroImportFormats))
	-- 1 -- realiza el mapeo de informacion de importaciones de allegro a nativos
	local nativeImportFormats, errors = m_importFormats:MakeNativeImportFormats(vcc, allegroImportFormats)
	--LogDebug("[FULLCONTACT.Migration.ImportFormats:Migrate] 3 - Migrating imports of VCC '%s'. nativeImportFormats-> %s.", vcc, json.encode(nativeImportFormats))
	--LogDebug("[FULLCONTACT.Migration.ImportFormats:Migrate] 4 - Migrating imports of VCC '%s'. errors-> %s.", vcc, json.encode(errors))
	if #errors == #allegroImportFormats then
		LogError("[FULLCONTACT.Migration.ImportFormats:Migrate] Unable to migrate all Allegro Import Formats. total %s.", #allegroImportFormats)
		return false, {err = "UNABLE TO MIGRATE ALL ALLEGRO IMPORT FORMATS", errors = errors}
	end
	-- start migration
	-- 2  comienza el proceso de migracion de los importaciones
	--
	errors = errors or {}
	for _, nativeImportFormat in ipairs(nativeImportFormats) do
		local success = m_fullcontact.Dialer:SaveImportFormat(nativeImportFormat, ksOE)
		if not success then
			local err = {err = "UNABLE TO MIGRATE ALLEGRO IMPORT FORMAT", importFormatId = nativeImportFormat.Id}
			table.insert(errors, err)
		end
	end
	-- ok
	LogDebug("[FULLCONTACT.Migration.ImportFormats:Migrate] 5 ---> Result of Migration Import Formats of VCC '%s'. isOK.", vcc)
	return true, errors
end

--[[
]]--
m_importFormats.Rollback = function (self, vcc, ksOE)
	assert(type(vcc) == "string")
	LogInfo("[FULLCONTACT.Migration.ImportFormats:Rollback]  1 -Rollbacking Native Import Formats of VCC '%s' to Allegro Import Formats.", vcc)
	local success, nativeImportFormats = m_model.Dialer.ListImportFormat({vcc = vcc}, ksOE)
	if not success then
		local err = {err = "UNABLE TO ROLLBACK NATIVE IMPORT FORMATS TO ALLEGRO - NO IMPORT FORMATS LIST FOR VCC", vcc = vcc}
		LogError("[FULLCONTACT.Migration.ImportFormats:Rollback] Unable to Rollback Native Import Formats. Err: %s.", json.encode(err))
		return false, err
	end
	for _, nativeImportFormat in ipairs(nativeImportFormats or {}) do
		local importIdWithVCC = m_helpers.AddVCC(nativeImportFormat.Id, vcc):lower()
		m_model.Dialer.RemoveImportFormat(importIdWithVCC, ksOE)
	end
	-- ok
	return true
end

--[[
]]--
m_importFormats.MakeNativeImportFormats = function (self, vcc, allegroImportFormats)
	assert(type(vcc) == "string")
	assert(type(allegroImportFormats) == "table")
	--LogDebug("[FULLCONTACT.Migration.ImportFormats:MakeNativeImportFormats]  Making ImportFormats Import Formats from Allegro for VCC '%s'. allegroImportFormats: %s", vcc, json.encode(allegroImportFormats))
	local errors = {}
	local nativeImportFormats = {}
	for _, allegroImportFormat in ipairs(allegroImportFormats) do
		local success, nativeImportFormat = m_importFormats:MakeNativeImportFormat(vcc, allegroImportFormat)
		if success then
			table.insert(nativeImportFormats, nativeImportFormat)
		else
			local err = nativeContact
			table.insert(errors, err)
		end
	end
	--ok
	return nativeImportFormats, errors
end

--[[
]]--
m_importFormats.MakeNativeImportFormat = function (self, vcc, allegroImportFormat)
	assert(type(vcc) == "string")
	assert(type(allegroImportFormat) == "table")
	--LogDebug("[FULLCONTACT.Migration.ImportFormats:MakeNativeImportFormat]  1 -Making Native Import Formats from Allegro Import Formats for VCC '%s'. allegroImportFormat: %s", vcc, json.encode(allegroImportFormat))

	-- 1- la importacion
	local nativeImportFormat = {
		-- SI - valores que llegan desde allegro
		Id                   = utf8.lower(allegroImportFormat.Id),
		VCC                  = vcc,
		Description          = allegroImportFormat.Description or "",
		-- NO - valores que no llegan desde allegro
		-- CreationDate         = os.time(),
		-- LastModificationDate = os.time(),
		UserId               = "migrator@system",
		-- Diferentes - a crear ya que los valores llegan diferentes desde allegro
		ContactImportFormatFields = {},
		ContactImportFormatKeys = {},
		-- Allegro - existen en Allegro pero no mapean en Nativo
		Allegro = {}
	}
	-- 2 - el detalle de la importacion
	for _, allegroField in ipairs(allegroImportFormat.ContactImportFormatFields or {}) do
		--[[
			Allegro:
				{
					"Type": 6,
					"Name": "AccountGroup",
					"VCC": 120,
					"Status": "ENABLED",
					"HeaderId": "todos1",
					"DisplayType": "Account Group"
				}
			Nativo:
				{
					"Type": 6,
					"Name": "AccountGroup",
					"id": "585F606E4EC0BA961B26F7475A97DC25",
					"TypeName": "ACCOUNTGROUP",
					"Status": "ENABLED"
				}
		]]--
		local nativeField = {
			-- SI - valores que llegan desde allegro
			Type     = allegroField.Type,
			Name     = allegroField.Name,
			Status   = allegroField.Status,
			-- NO - valores que no llegan desde allegro
			id    = uuid.new(),
			TypeName = nil, -- Este atributo se genera de forma automatica cuando se va a almacenar el importFormat en "fullcontact.lua" metodo "SaveImportFormat", se realiza segun los datos obtenidos en "LoadImportFieldsTypes"
			-- Diferentes - a crear ya que los valores llegan diferentes desde allegro
			-- ...
			-- Allegro - existen en Allegro pero no mapean en Nativo
			Allegro = {
				DisplayType          = allegroField.DisplayType,
				NumericVCC           = allegroField.VCC,
				HeaderId             = allegroField.HeaderId,
				-- Type 7 - ADDRESS -> PHONE
				PhoneExtensionColumn = allegroField.PhoneExtensionColumn,
				PhoneZIPColumn       = allegroField.PhoneZIPColumn,
				-- Type 12 - SCHEDULED CALL
				ScheduledFormat      = allegroField.ScheduledFormat,
				ScheduledTimezone    = allegroField.ScheduledTimezone
			}
		}
		-- Type 11 - NAMEVALUES
		if tostring(allegroField.Type) == "11" then
			nativeField.IsSearchable = true
			nativeField.SearchableDataType = "TEXT" -- tengo que agregar un valor defecto, ya que desde Allegro no tengo este tipo de valor a ser mapeado.
		end
		-- inserto en el array de campos de formatos
		table.insert(nativeImportFormat.ContactImportFormatFields, nativeField)
	end

	--LogDebug("[FULLCONTACT.Migration.ImportFormats:MakeNativeImportFormat]  2 -Maked Native Import Formats from Allegro Import Formats for VCC '%s'. Result -> nativeImportFormat: %s", vcc, json.encode(nativeImportFormat))
	--
	return true, nativeImportFormat
end

-------------------------------------------------------
-- ALLEGRO - BLACKLIST
-------------------------------------------------------

--[[
]]--
m_blackList.importId = "allegro_blacklist"

m_blackList.Migrate = function (self, vcc, blackList, ksOE, ksAgent)
	assert(type(vcc) == "string")
	assert(type(blackList) == "table")
	local totalContactsInBlacklist = #blackList
	--LogDebug("[FULLCONTACT.Migration.m_blackList:Migrate]  1 -Migrate Blacklist. VCC '%s'. Total Blacklist Addresses: %s", vcc, totalContactsInBlacklist)
	if totalContactsInBlacklist == 0 then
		return
	end
	local csvData = "ID\n" .. table.concat(blackList, "\n")
	--LogDebug("[FULLCONTACT.Migration.m_blackList:Migrate]  2 -Migrate Blacklist. VCC '%s'. Blacklist csvData: %s", vcc, csvData)
	local importInfo = {
		ID          = m_blackList.importId,
		AddressType = "PHONE",
		ScopeType   = "vcc", -- global or vcc
		VCC         = vcc, --"vcc1",
		UserId      = "migrator@system"
	}
	local success, response = m_blackListAPI:StartImport(importInfo, csvData, nil, ksOE)
	LogInfo("[FULLCONTACT.Migration.m_blackList:Migrate] result ---> success '%s', response: %s", success, json.encode(response))
	if success then
		local callCampaignsAccounts = m_blackList:GetCallCamaignsAccounts(vcc, ksAgent)
		m_blackList:AddRelatedCampaignsAccounts(vcc, callCampaignsAccounts, ksOE, ksAgent)
	end
end

--[[

]]--
m_blackList.MakeContactBlackList = function (self, vcc, allegroContact, addresses)
	assert(type(vcc) == "string")
	assert(type(allegroContact) == "table")
	assert(type(addresses) == "table")
	-- Desde Allegro en el JSON el campo boolean me puede llegar un 1 o 0 o un true/false
	local inBlackist = allegroContact.VIP and allegroContact.VIP or tonumber(allegroContact.VIP) == 1
	--LogDebug("[FULLCONTACT.Migration.m_blackList:MakeContactBlackList]  1 -Making Native Contact Addresses for BlackList from Allegro Contact for VCC '%s'. allegroContact.ID: %s, allegroContact.VIP: %s, inBlackist: %s", vcc, allegroContact.ID, allegroContact.VIP, inBlackist)
	if not inBlackist then
		-- el contacto NO se encuentra en la Blacklist de Allegro.
		return false
	end
	local phones = {}
	for _, address in ipairs(addresses) do
		if address.Type:upper() == "PHONE" then
			table.insert(phones, address.Number)
		end
	end
	local totalPhones = #phones
	--LogDebug("[FULLCONTACT.Migration.m_blackList:MakeContactBlackList]  2 -Making Native Contact Addresses for BlackList from Allegro Contact for VCC '%s'. allegroContact.ID: %s, inBlackist: %s, totalPhones: %s", vcc, allegroContact.ID, inBlackist, totalPhones)
	if totalPhones == 0 then
		-- el contacto SI se encuentra en la Blacklist de Allegro y NO tiene telefonos asignados.
		LogWarning("[FULLCONTACT.Migration.m_blackList:MakeContactBlackList] Unable to Make Native Contact In BlackList from Allegro Contact for VCC '%s'. allegroContact.ID: %s. Contact not has Assigned Phones.", vcc, allegroContact.ID)
		return false
	end
	-- el contacto se encuentra en la Blacklist de Allegro y tiene telefonos asignados.
	-- ok
	return true, phones
end

--[[

]]--
m_blackList.AddRelatedCampaignsAccounts = function(self, vcc, callCampaignsAccounts, ksOE, ksAgent)
	assert(type(vcc) == "string")
	assert(type(callCampaignsAccounts) == "table")
	LogInfo("[FULLCONTACT.Migration.m_blackList:AddRelatedCampaignsAccounts] Assign AllegroBlacklist '%s' to '%s' campaignsAccounts in VCC '%s'.", m_blackList.importId, #callCampaignsAccounts, vcc)
	local userId = "migrator@system"
	local oldBlacklists = {}
	local newBlacklists = {
		[m_blackList.importId] = {isGlobal = false}
	}
	for _, accountInfo in ipairs(callCampaignsAccounts) do
		--LogDebug("--> accountInfo: %s", json.encode(accountInfo or {}))
		m_blackList:UpdateCamaignAccountBlackList(vcc, accountInfo.campaignId, accountInfo.accountId, accountInfo.outgoingConfig, ksAgent)
		local success, response = m_blackListAPI:AddRelatedCampaignsAccounts(vcc, accountInfo.campaignId, accountInfo.accountId, oldBlacklists, newBlacklists, userId, ksOE)
		if success then
			-- ok
			LogInfo("1 - AddRelatedCampaignsAccounts SUCCESS assigned AllegroBlacklist to campaign '%s', account '%s'.", accountInfo.campaignId, accountInfo.accountId)
		else
			-- error
			LogInfo("2 - AddRelatedCampaignsAccounts ERROR assigning AllegroBlacklist to campaign '%s', account '%s'.", accountInfo.campaignId, accountInfo.accountId)
		end
	end
end

--[[
]]--
m_blackList.Rollback = function (self, vcc, ksOE, ksAgent)
	assert(type(vcc) == "string")
	local importId = m_blackList.importId
	LogInfo("[FULLCONTACT.Migration.ImportFormats:Rollback]  1 -Rollbacking Native Blacklist of VCC '%s'. blacklistId: %s.", vcc, importId)
	-- 1. elimino la relacion de la blacklist con las campanas/cuentas
	local callCampaignsAccounts = m_blackList:GetCallCamaignsAccounts(vcc, ksAgent)
	m_blackList:RemoveRelatedCampaignsAccounts(vcc, callCampaignsAccounts, ksAgent, ksOE)
	-- 2. elimino la blacklist de Allegro
	local success, err = m_blackListAPI:RemoveImport(importId, vcc, "migrator@system", ksOE)
	if success then
		-- ok
		LogInfo("1 - Removed Global Blacklist Result ---> SUCCESS, importId: %s", importId)
		return true
	end
	-- error
	LogWarning("2 - Removed Global Blacklist Result ---> ERROR, importId: %s. Err: %s", importId, json.encode(err or {}))
	return false
end

--[[

]]--
m_blackList.RemoveRelatedCampaignsAccounts = function(self, vcc, callCampaignsAccounts, ksAgent, ksOE)
	assert(type(vcc) == "string")
	assert(type(callCampaignsAccounts) == "table")
	LogDebug("[FULLCONTACT.Migration.m_blackList:RemoveRelatedCampaignsAccounts] Remove AllegroBlacklist '%s' from '%s' campaignsAccounts in VCC '%s'.", m_blackList.importId, #callCampaignsAccounts, vcc)
	local userId = "migrator@system"
	local blacklists = {
		[m_blackList.importId] = {isGlobal = false}
	}
	for _, accountInfo in ipairs(callCampaignsAccounts) do
		local success, err = m_blackListAPI:RemoveRelatedCampaignsAccounts(vcc, accountInfo.campaignId, accountInfo.accountId, blacklists, userId, ksOE)
		if success then
			-- ok
			LogInfo("1 - RemoveRelatedCampaignsAccounts SUCCESS removed AllegroBlacklist from campaign '%s', account '%s'.", accountInfo.campaignId, accountInfo.accountId)
		else
			-- error
			LogInfo("2 - RemoveRelatedCampaignsAccounts ERROR removing AllegroBlacklist from campaign '%s', account '%s'.", accountInfo.campaignId, accountInfo.accountId)
		end
	end
end

--[[

]]--
m_blackList.UpdateCamaignAccountBlackList = function(self, vcc, campaignId, accountId, outgoingConfig, ksAgent)
	assert(type(vcc) == "string")
	assert(type(campaignId) == "string")
	assert(type(accountId) == "string")
	assert(type(outgoingConfig) == "table")
	local _, scopeId = m_blackListAPI:MakeScopeInfo("vcc", vcc, m_blackList.importId)
	outgoingConfig.Blacklists = {
		enabled = true,
		scopes = {
			[scopeId] = {isGlobal = false}
		}
	}
	local encodedOutgoingConfig = m_helpers.JSON_Encode(outgoingConfig)
	LogInfo("[FULLCONTACT.Migration.m_blackList:UpdateCamaignAccountBlackList] ==> vcc: %s, campaignId: %s, accountId: %s, outgoingConfig: '%s'.", vcc, campaignId, accountId, encodedOutgoingConfig)
	ksAgent:InsertSuperColumn(campaignId, "CampaignAccounts", accountId, "outgoingConfig", encodedOutgoingConfig)
end

--[[
	Response: {
		{
			campaignId = "camptel2@emmatel2",
			accountId  = "CALL_camptel2@emmatel2_camptel2"
		},
		{
			campaignId = "camptel3@emmatel2",
			accountId  = "CALL_camptel3@emmatel2_camptel3"
		},
		..
	}
]]--
m_blackList.GetCallCamaignsAccounts = function(self, vcc, ksAgent)
	assert(type(vcc) == "string")
	local callCampaignsAccounts = {}
	local vccCampaigns = m_model.Campaigns:GetVCCCampaigns(vcc, ksAgent)
	for campaignId in pairs(vccCampaigns) do
		local accounts, fullCampaignId = m_model.Campaigns:GetCampaignAccounts(campaignId, vcc, ksAgent)
		for _, account in pairs(accounts) do
			if account.proxyType == "CALL" then
				table.insert(callCampaignsAccounts, {
					campaignId     = fullCampaignId,
					accountId      = account.id,
					outgoingConfig = m_helpers.JSON_Decode(account.outgoingConfig)
				})
			end
		end
	end
	--LogDebug("[FULLCONTACT.Migration.m_blackList:GetCallCamaignsAccounts] ==> vcc: %s, callCampaignsAccounts: '%s'.", vcc, json.encode(callCampaignsAccounts))
	return callCampaignsAccounts
end

------------------------------------------
--
-- Exported functions
--
return {
	Init = m_migrations.Init,
	Allegro = {
		-- contactos
		Contacts = {
			Migrate  = m_contacts.Migrate,
			Rollback = m_contacts.Rollback
		},
		-- importaciones
		Imports = {
			Migrate  = m_imports.Migrate,
			Rollback = m_imports.Rollback
		},
		-- formatos de importacion
		ImportFormats = {
			Migrate  = m_importFormats.Migrate,
			Rollback = m_importFormats.Rollback
		}
	}
}
