local m_template_parser = require("Module:template parser")

local build_template = m_template_parser.buildTemplate
local concat = table.concat
local get_template_invocation_name = m_template_parser.getTemplateInvocationName
local insert = table.insert
local is_valid_title = require("Module:pages").is_valid_title
local new_title = mw.title.new
local shallowcopy = require("Module:table").shallowcopy

local is_substing = mw.isSubsting()

local function unsubst_me(frame)
	return frame.args[""]
end

local function get_title(frame)
	local title = new_title(frame:getTitle())
	if not is_valid_title(title) then
		-- Only possible if the frame has been tampered with.
		error("frame returned an invalid title.")
	end
	return title
end

local function serialize(title, args)
	return "{{" .. concat(build_template(title, args), "|") .. "}}"
end

local mt = {}

function mt:__index(entry_point)
	-- Cannot unsubst if not currently being substed.
	if not is_substing then
		local frame_title = mw.getCurrentFrame():getTitle()
		if frame_title ~= "Modul:unsubst" then
			error(("[[%s]] should not call [[Module:unsubst]] unless mw.isSubsting() returns true."):format(frame_title))
		-- Allow {{#invoke:unsubst|me|=...}}.
		elseif entry_point == "me" then
			return unsubst_me
		end
		return
	end
	return function(frame)
		local parent = frame:getParent()
		if parent:getTitle() ~= mw.title.getCurrentTitle().fullText then
			return serialize(get_template_invocation_name(get_title(parent)), parent.args)
		end
		local args = shallowcopy(frame.args)
		insert(args, 1, entry_point)
		local title = get_title(frame)
		-- Only possible if with mw.getCurrentFrame has been tampered with.
		if title.namespace ~= 828 then
			error("[[Modul:unsubst]] cannot work if the current frame is not in the " .. mw.site.namespaces[828].canonicalName .. " namespace, because the #invoke magic word requires it.")
		end
		return serialize("safesubst:<noinclude/>#invoke:" .. title.text, args)
	end
end

return setmetatable({}, mt)