local utf8 = require "icu.utf8"

local AddressMapper = {}

local function SanitizeId (id, channel)
	if not id then
		return ""
	end
	channel = channel or ""
	id = tostring(id)
	if channel:upper() == "MAIL" then
		-- Para que ES pueda encontrar un mail en la busqueda debe sanitizar y eliminar el @ ya que sino encuentra el nombre sin el @dominio.com
		id = id:gsub("@", ":")
	end
	return id:lower()
end
AddressMapper.SanitizeId = SanitizeId

local function MakeChannels (sourceChannels)
	local helpers = require "fullcontact.helpers"
	-- No deberia llegar nunca un JSON, sino que deberia llegar una tabla, pero por las dudas nos cubrimos.
	sourceChannels = helpers.JSON_Decode(sourceChannels)
	if type(sourceChannels) ~= "table" then
		return
	end
	local channels
	for _, channel in ipairs(sourceChannels) do
		channels = channels or {}
		table.insert(channels, utf8.upper(channel))
	end
	return channels
end
AddressMapper.MakeChannels = MakeChannels

local function ValidatePhone (number, country, area, vcc, withTimezone, withTrace, options)
	local helpers = require "fullcontact.helpers"
	return helpers.validation:IsPhone(number, country, area, vcc, withTimezone, withTrace, options)
end

--
-- Each address mapper takes a table describing an address and returns a table
-- describing what needs to be written to Cassandra, plus the value used to
-- index this address in the i6index
--
--[[
		{
			"Number": "+59899925895",
			"Type": "Phone",
			"Extension": "",
			"Country": "598",
			"LocalNumber": "099925895",
			"SanitizedId": "+59899925895",
			"Kind": "",
			"displayable": "+59899925895",
			"Area": "99",
			Channels = {"CALL", "SMS"}
		}
]]--
function AddressMapper.phone (address, vcc, options)
	options = options or {}
	options.addressDetail = address
	local phoneNumber = tostring(address.Number or address.address)
	local isValidPhone, validation = ValidatePhone(phoneNumber, address.Country, address.Area, vcc, nil, nil, options)
	local err
	-- validation: {"number":"24000007","dialLocal":"24000007","dialGlobal":"59824000007","dialSameCountry":"24000007","countryCode":"598","areaCode":""}
	if not isValidPhone then
		err = validation
		--LogWarning("[FULLCONTACT.address_mapper:AddressMapper.phone] --> Phone validation error: %s", json.encode(err or {}))
	end
	phoneNumber = validation.dialGlobal or phoneNumber
	local firstCharacter = phoneNumber:sub(1, 1)
	if firstCharacter ~= "+" then
		phoneNumber = "+" .. phoneNumber
	end
	local defaultChannels = {"CALL"}
	local data_to_store = {
		Type         = "Phone",
		-- phone validation response
		Number       = tostring(phoneNumber),
		Country      = validation.countryCode or address.Country or "",
		Area         = validation.areaCode or address.Area or "",
		LocalNumber  = validation.dialLocal or address.LocalNumber or "",
		SimpleNumber = validation.number or address.LocalNumber or "",
		SameCountry  = validation.dialSameCountry or address.Country or "",
		Validation   = {
			Success = isValidPhone and true or false,
			Error   = err
		},
		----
		SanitizedId  = SanitizeId(phoneNumber, "CALL"),
		Extension    = address.Extension or address.extension or "",
		Kind         = address.Kind or address.addressSubType or "", -- (CELLULAR, HOME, OFFICE)
		displayable  = phoneNumber,
		ZipPhone     = address.ZipPhone or "",
		Status       = address.Status or "Enabled",
		Channels     = MakeChannels(address.Channels or defaultChannels)
	}
	local helpers = require "fullcontact.helpers"
	local _, addressId = helpers.BuildAddressId(data_to_store.Type, data_to_store, vcc, options)
	data_to_store.AccountId = addressId
	local index_key = phoneNumber
	--LogDebug("[FULLCONTACT.address_mapper:AddressMapper.phone] END -> index_key: '%s' data_to_store: %s", index_key, json.encode(data_to_store))
	return data_to_store, index_key
end

function AddressMapper.im (address, vcc)
	local defaultChannels = {} -- TODO: agregar los canales por defecto que correspondan. Cuando el canal sea implementado.
	local data_to_store = {
		SanitizedId = SanitizeId(address.buddy, "IM"),
		Type = "IM",
		protocol = address.protocol,
		buddy = address.buddy,
		displayable = address.buddy,
		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
		}
	}
	local index_key = address.buddy
	return data_to_store, index_key
end

function AddressMapper.facebook (address, vcc)
	local defaultChannels = {} -- TODO: agregar los canales por defecto que correspondan. Cuando el canal sea implementado.
	local data_to_store = {
		SanitizedId = SanitizeId(address.UID, "FACEBOOK"),
		Type = "Facebook",
		UID = tostring(address.UID),
		displayable = tostring(address.UID),
		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
		}
	}
	local index_key = address.UID
	return data_to_store, index_key
end

function AddressMapper.instagram (address, vcc)
	local defaultChannels = {} -- TODO: agregar los canales por defecto que correspondan. Cuando el canal sea implementado.
	local data_to_store = {
		SanitizedId = SanitizeId(address.UID, "INSTAGRAM"),
		Type = "Instagram",
		UID = tostring(address.UID),
		displayable = tostring(address.UID),
		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
		}
	}
	local index_key = address.UID
	return data_to_store, index_key
end

function AddressMapper.youtube (address, vcc)
	local defaultChannels = {} -- TODO: agregar los canales por defecto que correspondan. Cuando el canal sea implementado.
	local data_to_store = {
		SanitizedId = SanitizeId(address.UID, "YOUTUBE"),
		Type = "Youtube",
		UID = tostring(address.UID),
		displayable = tostring(address.UID),
		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
		}
	}
	local index_key = address.UID
	return data_to_store, index_key
end

function AddressMapper.appstore (address, vcc)
	local defaultChannels = {} -- TODO: agregar los canales por defecto que correspondan. Cuando el canal sea implementado.
	local data_to_store = {
		SanitizedId = SanitizeId(address.UID, "APPSTORE"),
		Type = "Appstore",
		UID = tostring(address.UID),
		displayable = tostring(address.UID),
		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
		}
	}
	local index_key = address.UID
	return data_to_store, index_key
end

function AddressMapper.googleplay (address, vcc)
	local defaultChannels = {} -- TODO: agregar los canales por defecto que correspondan. Cuando el canal sea implementado.
	local data_to_store = {
		SanitizedId = SanitizeId(address.UID, "GOOGLEPLAY"),
		Type = "Googleplay",
		UID = tostring(address.UID),
		displayable = tostring(address.UID),
		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
		}
	}
	local index_key = address.UID
	return data_to_store, index_key
end

function AddressMapper.twitter (address, vcc)
	local defaultChannels = {} -- TODO: agregar los canales por defecto que correspondan. Cuando el canal sea implementado.
	local data_to_store = { Type = "Twitter" }
	for k, v in pairs(address) do
		data_to_store[k] = tostring(v)
	end
	data_to_store.displayable = address.User and tostring(address.User) or nil
	local index_key = address.User and tostring(address.User) or ""
	data_to_store.SanitizedId = SanitizeId(index_key, "TWITTER")
	data_to_store.Status = address.Status or "Enabled"
	data_to_store.Channels = MakeChannels(address.Channels or defaultChannels)
	-- TODO: Realizar validacion ? Si no se realiza la validacion, la estructura Validation tiene que viajar igual
	data_to_store.Validation = {
		Success = true,
		Error   = nil
	}
	return data_to_store, index_key
end

function AddressMapper.mail (address, vcc)
	local defaultChannels = {"MAIL"}
	local data_to_store = {
		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
		}
	}
	local index_key = address.address
	return data_to_store, index_key
end

return AddressMapper
