Module documentation
require('strict')

local p = {}

-- Return a title using [[Special:MyLanguage]], which resolves to user language
-- at read time if that exists, or English otherwise
local function getMyLanguage(title)
	return mw.title.new('Special:MyLanguage/' .. title.fullText)
end

-- Return the given property of the title object. Return false when exceeding
-- the expensive parser function limit instead of throwing.
local function safeProperty(title, prop)
	local success, result = pcall(function () return title[prop] end)
	return success and result
end

-- Get display title for pages translated using the Translate extension
local function getDisplayTitle(title, lang)
	local titlepage = mw.title.makeTitle('Translations', title.prefixedText .. '/Page display title/' .. lang)
	-- expandTemplate throws if the page doesn’t exist
	local success, display = pcall(function () return mw.getCurrentFrame():expandTemplate{ title = titlepage } end)
	if success then
		if title.fragment ~= '' then
			display = display .. '#' .. title.fragment
		end
		return display
	else
		return nil
	end
end

-- Common part used by p.main() and p.pg2()
function p.getLink(page, display, anchor, lang, useMyLanguage)
	-- Sort out things like nil, object etc. It is likely to be invalid title,
	-- but c’est la vie.
	local title = mw.title.new(tostring(page or ''))
	if not title then
		return '[['  .. page .. ']]'
	end
	if anchor then
		title.fragment = anchor
	end
	if safeProperty(title, 'isRedirect') then
		local fragment = title.fragment
		title = title.redirectTarget
		if fragment ~= '' then
			title.fragment = fragment
		end
	end
	if useMyLanguage then
		-- using the user's prefered language for the UI
		if not display then
			display = getDisplayTitle(title, lang) or title.fullText
		end
		title = getMyLanguage(title)
	else
		-- using the current page content language
		if lang ~= 'en' then
			local subpage = title:subPageTitle(lang)
			if safeProperty(subpage, 'exists') then
				-- version of target page exists in current page language, return that version
				subpage.fragment = title.fragment
				if not display then
					-- try to use translated page title
					display = getDisplayTitle(title, lang)
				end
				title = subpage
			else
				-- prepend Special:MyLanguage/ to return the target page in
				-- user’s preferred language if available
				if not display then
					display = title.fullText
				end
				title = getMyLanguage(title)
			end
		end
	end
	return '[['  .. title.fullText .. (display and '|' .. display or '') .. ']]'
end

-- Variant using the current page language (possibly translated manually or with
-- the translation extension), not the current user's UI language.
function p.main(frame)
	local args = require('Module:Arguments').getArgs(frame, {frameOnly = true})
	--[=[
	{{PAGELANGUAGE}} only works on pages prepared with the Translate extension
	and with other pages that have their page language set manually. If you can’t
	use the Translate extension for some reason, ask translation administrators
	at [[Meta talk:Babylon]] to change the page language manually.
	--]=]
	local lang = args.lang or mw.getCurrentFrame():preprocess('{{PAGELANGUAGE}}')
	return p.getLink(args.page, args.display, args.anchor, lang, false)
end

-- Variant using the user's UI language ("Special:MyLanguage/*" after resolving redirects),
-- not the current page language.
function p.pg2(frame)
	local args = require('Module:Arguments').getArgs(frame, {frameOnly = true})
	local lang = args.lang or mw.getCurrentFrame():preprocess('{{Int:Lang}}')
	return p.getLink(args[1], args[2], args.anchor, lang, true)
end

return p