Документация
local p = {}

function p.getArgs( frame )
	if not frame then
		return {}
	end

	local args = {}

	local p_frame = frame:getParent()
	if p_frame and p_frame.args then
		args = p_frame.args
	end

	if frame.args and frame.args then
		for key, value in pairs( frame.args ) do
		    args[key] = value
		end
	end

	return args
end

function p.getEntityId( frame )
	local args = p.getArgs( frame )
	if args and args.from and string.gmatch( args.from, '^Q\d+$' ) then
		return args.from
	end

	return mw.wikibase.getEntityIdForCurrentPage()
end

function p.getDefaultTemplate( frame )
	if frame and frame.args and frame.args.default and default ~= '' then
		return frame.args.default
	end
	return ''
end


local function getEntityIdsFromStatement( entityId, propertyId )
	local entityIds = {}
	local statements = mw.wikibase.getBestStatements( entityId, propertyId );
	if statements then
		for _, statement in ipairs( statements ) do
			if statement and statement.mainsnak and statement.mainsnak.snaktype == 'value' then
				table.insert( entityIds, statement.mainsnak.datavalue.value.id )
			end
		end
	end

	return entityIds
end

local function isInfobox( entityId )
	local instanceOfIds = getEntityIdsFromStatement( entityId, 'P31' )
	for _, instanceOfId in ipairs( instanceOfIds ) do
		if instanceOfId == 'Q19887878' then
			return true
		end
	end
	return false
end

local function getLinkedTemplateName( entityId )
	local statements = mw.wikibase.getBestStatements( entityId, 'P1424' );
	if not statements then
		return nil
	end

	for _, statement in ipairs( statements ) do
		if statement and statement.mainsnak and statement.mainsnak.snaktype == 'value' then
			local templateEntityId = statement.mainsnak.datavalue.value.id
			if isInfobox( templateEntityId ) then
				local templateName = mw.wikibase.getSitelink( templateEntityId, 'ruwiki' )
				if templateName then
					return templateName
				end
			end
		end
	end
	return nil
end

local function getLinkedTemplateNameRecursive( entityId, fromOccupation )
	local entityIds = {
		Q4164871 = true,
	}
	local isNew = true
	
	local instanceProperty = 'P31'
	if fromOccupation then
		instanceProperty = 'P106'
		entityIds['Q5'] = true -- человек
		entityIds['Q28640'] = true -- профессия
		entityIds['Q215627'] = true -- личность
	end
	local instanceEntityIds = getEntityIdsFromStatement( entityId, instanceProperty )
	for _, instanceEntityId in ipairs( instanceEntityIds ) do
		entityIds[instanceEntityId] = false
		if not fromOccupation and instanceEntityId == 'Q5' then
			local templateName = getLinkedTemplateNameRecursive( entityId, true )
			if templateName then
				return templateName
			end
		end
	end

	while isNew do
		isNew = false
		for entityId, isChecked in pairs( entityIds ) do
			if not isChecked then
				local templateName = getLinkedTemplateName( entityId )
				if templateName then
					return templateName
				end
				local parentEntityIds = getEntityIdsFromStatement( entityId, 'P279' )
				for _, parentEntityId in ipairs( parentEntityIds ) do
					if entityIds[parentEntityId] == nil then
						entityIds[parentEntityId] = false
						isNew = true
					end
				end
				entityIds[entityId] = true
			end
		end
	end
	
	return nil
end

function p.getTemplateName( frame )
	local entityId = p.getEntityId( frame )
	if entityId then
		local templateName = getLinkedTemplateNameRecursive( entityId )
	end
	local wdStatus, templateName = pcall( getLinkedTemplateNameRecursive, entityId )
	if wdStatus ~= true or not templateName or templateName == '' then
		return p.getDefaultTemplate( frame )
	end
	
	local nsName = mw.site.namespaces[10].name
	templateName = mw.ustring.gsub( templateName, '^' .. nsName .. ':', '' )
	
	return templateName
end

function p.getTemplateString( frame )
	local templateString = p.getTemplateName( frame )
	local args = p.getArgs( frame )
	if args.from and args.from ~= '' then
		templateString = templateString .. '|from=' .. args.from
	end
	if args.nocat and args.nocat ~= '' then
		templateString = templateString .. '|nocat=' .. args.nocat
	end

	return templateString
end

function p.render( frame )
	local args = p.getArgs( frame )
	
	local templateName = p.getTemplateName( frame )
	if templateName == '' then
		return ''
	end
	
	return frame:expandTemplate{
		title = templateName,
		args = { from = args.from, nocat = args.nocat }
	}
end

return p