require "Амодуль:No globals"

local p = {}

local lib = require 'Амодуль:Wikidata/lib'

-- @const
local br_split = '%s*<[^<>%w]-br[^<>%w]->%s*'

local function in_array(value, array)
	for _, val in ipairs(array) do
		if val == value then
			return true
		end
	end
	return false
end

local function stripBrackets(text)
	return mw.ustring.gsub(text, '%s*%([^%)]+%)', '')
end

local function markValue(value, as, options)
	return '<span class="wd-' .. as .. '">' .. value .. '</span>',
		lib.category(as, options.catbase or ('Vlastnost ' .. options.property))
end

function p.compareValues(value, Statements, options)
	if value == '' then
		return nil, nil
	end
	local title = mw.title.getCurrentTitle()
	if title.namespace ~= 0 and title.namespace ~= 14 then
		return nil, nil
	end

	if #Statements == 0 then
		return markValue(value, 'not', options)
	end

	local datatype = Statements[math.random(#Statements)].mainsnak.datatype
	local temp_value = mw.ustring.gsub(value, '<([a-z]+)%f[^%w][^>]->.-</%1>%s*', '')
	if datatype == "commonsMedia" or datatype == "string" or datatype == "external-id" then
		for _, statement in ipairs(Statements) do
			if lib.IsSnakValue(statement.mainsnak) then
				local temp_value = stripBrackets(temp_value)
				if tostring(statement.mainsnak.datavalue.value) == tostring(temp_value) then --TODO: normalizing
					return markValue(value, 'same', options)
				end
			end
		end
		return markValue(value, 'diff', options)
	elseif datatype == "monolingualtext" then
		for _, statement in ipairs(Statements) do
			if lib.IsSnakValue(statement.mainsnak) then
				if statement.mainsnak.datavalue.value.text == mw.text.strip(temp_value) then
					return markValue(value, 'same', options)
				end
			end
		end
		return markValue(value, 'diff', options)
	elseif datatype == "quantity" then
		if mw.ustring.match(temp_value, '%d+') then
			for number in mw.ustring.gmatch(value, '(%-?%d+)') do
				for _, statement in ipairs(Statements) do
					if lib.IsSnakValue(statement.mainsnak) then
						local lowerBound = tonumber(statement.mainsnak.datavalue.value.lowerBound)
						local upperBound = tonumber(statement.mainsnak.datavalue.value.upperBound)
						number = tonumber(number)
						if number >= lowerBound and number <= upperBound then
							return markValue(value, 'same', options)
						end
					end
				end
				break -- only the first one
			end
		end
		return markValue(value, 'diff', options)
	elseif datatype == "time" then
		temp_value = mw.ustring.gsub(temp_value, '%[%[%s*([^|%]]+)%s*[^%]]*%]%]', '%1')
		temp_value = stripBrackets(mw.ustring.lower(temp_value))
		local Time = require 'Амодуль:Time'
		local Months = {
			["ажьырныҳәамза"] = 1,
			["жәабранмза"] = 2,
			["хәажәкырамза"] = 3,
			["мшаԥымза"] = 4,
			["лаҵарамза"] = 5,
			["рашәарамза"] = 6,
			["ԥхынгәымза"] = 7,
			["нанҳәамза"] = 8,
			["цәыббрамза"] = 9,
			["жьҭаарамза"] = 10,
			["абҵарамза"] = 11,
			["ԥхынҷкәынмза"] = 12,
		}
		for _, statement in ipairs(Statements) do
			if lib.IsSnakValue(statement.mainsnak) then
				local timevalue = Time.newFromWikidataValue(statement.mainsnak.datavalue.value)
				if timevalue then
					for parsed in mw.text.gsplit(temp_value, br_split) do
						parsed = mw.ustring.sub(parsed, 1, mw.ustring.match(parsed, '%d?%d%d()%d') or -1)
						local parsedTable = {}
						for _, value in ipairs(mw.text.split(parsed, '[^%w]+')) do
							if tonumber(value) then
								table.insert(parsedTable, tonumber(value))
							else
								if Months[value] then
									table.insert(parsedTable, 2, Months[value])
								else
									parsedTable = {}
									break
								end
							end
						end
						local Table
						if #parsedTable == 1 then
							Table = Time.new{
								year = parsedTable[1]
							}
						elseif #parsedTable == 2 then
							Table = Time.new{
								year = parsedTable[1],
								month = parsedTable[2]
							}
						elseif #parsedTable == 3 then
							Table = Time.new{
								year = math.max(parsedTable[1], parsedTable[3]),
								month = parsedTable[2],
								day = math.min(parsedTable[1], parsedTable[3])
							}
						end
						if not Table then
							mw.log('Аамҭарба аилыргара аманшәалахом ' .. parsed)
						else
							if timevalue == Table then
								return markValue(value, 'same', options)
							end
						end
					end
				end
			end
		end
		return markValue(value, 'diff', options)
	elseif datatype == "url" then
		if not mw.ustring.match(temp_value, 'https?://') then
			return markValue(value, 'diff', options)
		end
		local WDValues = {}
		for _, statement in ipairs(Statements) do
			if lib.IsSnakValue(statement.mainsnak) then
				table.insert(WDValues, statement.mainsnak.datavalue.value)
			end
		end
		for url in mw.ustring.gmatch(temp_value, '(https?://[^%[%]%s]+)') do
			if not in_array(url, WDValues) then
				return markValue(value, 'diff', options)
			end
		end
		return markValue(value, 'same', options)
	elseif datatype == "wikibase-item" then
		local WDValues, parsedValues = {}, {}
		for _, statement in ipairs(Statements) do
			if lib.IsSnakValue(statement.mainsnak) then
				local id = lib.getEntityIdFromValue(statement.mainsnak.datavalue.value)
				local value = mw.wikibase.sitelink(id) or mw.wikibase.label(id)
				if value then
					table.insert(WDValues, lib.common.firstToUpper(value))
				end
			end
		end
		local link_match = '%[%[[^%]%[]-%]%]'
		local link_target = '%[%[%s*([^|%]]-)%s*[|%]]'
		if mw.ustring.match(temp_value, br_split) then
			for value in mw.text.gsplit(temp_value, br_split) do
				local value = stripBrackets(value)
				if mw.ustring.match(value, link_match) then
					for page in mw.ustring.gmatch(value, link_target) do
						table.insert(parsedValues, lib.common.firstToUpper(page))
					end
				else
					table.insert(parsedValues, mw.text.trim(value))
				end
			end
		elseif mw.ustring.match(temp_value, link_match) then
			for value in mw.ustring.gmatch(temp_value, link_target) do
				table.insert(parsedValues, lib.common.firstToUpper(value))
			end
		else
			table.insert(parsedValues, mw.text.trim(temp_value))
		end
		if #parsedValues == 0 then
			return markValue(value, 'diff', options)
		end
		for _, parsed in ipairs(parsedValues) do
			if not in_array(parsed, WDValues) then
				return markValue(value, 'diff', options)
			end
		end
		return markValue(value, 'same', options)
	end
	--elseif datatype == "globecoordinate" then
	return nil, nil
end

return p