local export = {}

local m_languages = require("Module:languages")
local scripts_module = "Module:scripts"

local rsplit = mw.text.split


local function categorize(lang, source, root, id)
	local categories = {}

	local root_suffix = " root " .. root .. (id and " (" .. id .. ")" or "")
	if source then
		root_suffix = "the " .. source:getCanonicalName() .. root_suffix
	else
		root_suffix = "the" .. root_suffix
	end

	if not lang then
		return "Terms derived from " .. root_suffix
	elseif source then
		return lang:getCanonicalName() .. " terms derived from " .. root_suffix
	else
		return lang:getCanonicalName() .. " terms belonging to " .. root_suffix
	end
end


function export.rootsee(frame)
	local params = {
		[1] = {},
		[2] = {},
		[3] = {},
		["id"] = {},
		["mode"] = {}, -- one of "categories", "pages", "all" or "parents"; defaults to "all"; see [[mw:Extension:CategoryTree]].
		["pagename"] = {}, -- for testing and documentation pages
	}

	local args = require("Module:parameters").process(frame:getParent().args, params)
	local title

	if args.pagename then -- for testing, doc pages, etc.
		title = mw.title.new(args.pagename)
		if not title then
			error(("Bad value for pagename=: '%s'"):format(args.pagename))
		end
	else
		title = mw.title.getCurrentTitle()
	end

	if title.nsText == "Template" and title.subpageText == "rootsee" and not args[1] and not args[2] and not args[3] then
		args = {
			[1] = "en",
			[2] = "ine",
			[3] = "gʷem",
		}
	end
		
	local function convert_plus(val)
		if val == "+" then
			return nil
		else
			return val
		end
	end

	local lang = convert_plus(args[1])
	if lang then
		lang = m_languages.getByCode(lang, 1)
	end

	local source = convert_plus(args[2])
	local orig_source = source
	if source then
		source = m_languages.getByCode(source, 1, nil, "allow family")
		if source:hasType("family") then
			source = source:getProtoLanguage()
			if not source then
				error(("Family '%s' has no proto-language"):format(args[2]))
			end
		end
	elseif lang then
		source = lang
	elseif title:inNamespace("Reconstruction") or title:inNamespace("Appendix") then
		local langname = title.text:match("^(.-)/")
		if not langname then
			error(("Unable to infer source from pagename '%s' as it isn't doesn't have a current language in it (no slash)")
				:format(title.fullText))
		end
		source = m_languages.getByCanonicalName(langname)
		if not source then
			error(("Unable to infer source from pagename '%s' as current language '%s' isn't recognized as a language name")
				:format(title.fullText, langname))
		end
	else
		error(("Unable to infer source from pagename '%s' as it isn't a Reconstruction or Appendix page"):format(
			title.fullText))
	end

	local root = convert_plus(args[3])
	if not root then
		root = title.subpageText
		-- If none of dest lang, source lang and root were given, we're being asked to display a category of the form
		-- [[:Category:Terms derived from the Source root *root-]] where `root` comes from the current page. If this
		-- page is a Reconstruction page, make the root reconstructed even if the source language isn't
		-- reconstruction-only. This is definitely an edge case but is parallel to the derivsee() code in
		-- [[Module:affix/templates]].
		if not lang and not orig_source and title:inNamespace("Reconstruction") and not root:find("^%*") then
			root = "*" .. root
		end
	end

	if not root:find(" ") and not root:find("%-") then
		local is_latin = root:find("^[ -~]$")
		if not is_latin then
			local sc = require(scripts_module).findBestScriptWithoutLang(root)
			if sc and sc:getCode():find("Lat") then -- Latn, Latf, Latg, pjt-Latn
				is_latin = true
			end
		end
		if is_latin then
			if source:getCode() == "nv" then
				root = "-" .. root
			else
				root = root .. "-"
			end
		end
	end
	if source:hasType("reconstructed") and not root:find("^%*") then
		root = "*" .. root
	end

	if source and lang and source:getCode() == lang:getCode() then
		source = nil
	end

	return frame:callParserFunction{
		name = "#categorytree",
		args = {
			categorize(lang, source, root, args.id),
			depth = 0,
			class = '"derivedterms"',
			mode = args.mode or "all",
			hideprefix = "always",
			showcount = "on",
		}
	}
end

return export