local lang = require("Module:languages").getByCode("gmw-pro")

local export = {}

local genders = {
	["m"] = "陽性",
	["f"] = "陰性",
	["n"] = "中性",
}

local function detect_j(stem)
	-- match long vowel or diphthong followed by consonants
	local rest, nucleus, coda = mw.ustring.match(stem, "^(.-)([āēīōūąįų]?̄?[aeiou]*)([bdfghjklmnprʀstþw]+)$")

	if not rest or nucleus == "" then
		error("Stem does not end in a vowel or diphthong followed by consonants")
	elseif mw.ustring.len(coda) > 1 or mw.ustring.find(nucleus, "^[āēīōūąįų]̄?$") or mw.ustring.find(nucleus, "^[aeiou][aeiou]$") then
		return "ij"
	elseif mw.ustring.find(rest, "^[bdfghjklmnprʀstþw]*$") then
		return "j"
	else
		error("Stem consists of multiple syllables or its weight cannot be otherwise be determined")
	end
end

local function geminate(stem)
	stem = mw.ustring.gsub(stem, "w$", "uw")
	stem = mw.ustring.gsub(stem, "([bdghklmnpstþ])$", "%1%1")
	return stem
end


-- Inflection functions

function export.a(frame)
	local params = {
		[1] = {default = mw.title.getCurrentTitle().nsText == "Template" and "{{{1}}}" or mw.title.getCurrentTitle().subpageText},
		
		["g"] = {required = true, default = "m"},
		["n"] = {},
	}
	
	local args = require("Module:parameters").process(frame:getParent().args, params)
	
	if not (args["g"] == "m" or args["g"] == "n") then
		error("g= must be m or n")
	end
	
	local data = {
		forms = {},
		info = nil,
		categories = {},
	}

	local stem, suffix = mw.ustring.match(args[1], "^(.-)([iīu])$")
	local stem_u

	if suffix == "ī" then
		stem = stem .. "ij"
		data.info = "''ja''-詞幹"
		table.insert(data.categories, lang:getCanonicalName() .. "ja-詞幹名詞")
	elseif suffix == "i" then
		stem = geminate(stem) .. "j"
		data.info = "''ja''-詞幹"
		table.insert(data.categories, lang:getCanonicalName() .. "ja-詞幹名詞")
	elseif suffix == "u" then
		stem_u = stem
		stem = stem .. "w"
		data.info = "''wa''-詞幹"
		table.insert(data.categories, lang:getCanonicalName() .. "wa-詞幹名詞")
	else
		stem = args[1]
		data.info = "''a''-詞幹"
		table.insert(data.categories, lang:getCanonicalName() .. "a-詞幹名詞")
	end
	
	stem_u = stem_u or stem
	data.info = genders[args["g"]] .. " " .. data.info
	
	data.forms["nom|s"] = {args[1]}
	data.forms["acc|s"] = {args[1]}
	data.forms["gen|s"] = {stem .. "as"}
	data.forms["dat|s"] = {stem .. "ē"}
	data.forms["ins|s"] = {stem_u .. "u"}
	
	data.forms["nom|p"] = args["g"] == "n" and {stem_u .. "u"} or {stem .. "ō", stem .. "ōs"}
	data.forms["acc|p"] = args["g"] == "n" and {stem_u .. "u"} or {stem .. "ā"}
	data.forms["gen|p"] = {stem .. "ō"}
	data.forms["dat|p"] = {stem_u .. "um"}
	data.forms["ins|p"] = {stem_u .. "um"}

	postprocess(args, data)
	return make_table(data)
end

function export.an(frame)
	local params = {
		[1] = {default = mw.title.getCurrentTitle().nsText == "Template" and "{{{1}}}ō" or mw.title.getCurrentTitle().subpageText},
		
		["n"] = {},
	}

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

	local data = {
		forms = {},
		info = "''an''-詞幹",
		categories = {lang:getCanonicalName() .. "an-詞幹名詞"},
	}

	local stem, suffix = mw.ustring.match(args[1], "^(.-)([āō])$")
	local g

	if suffix == "ā" then
		g = "n"
	elseif suffix == "ō" then
		g = "m"
	else
		error("an-stems must end in -ō or -ā")
	end
	
	data.info = genders[g] .. " " .. data.info
	
	data.forms["nom|s"] = {args[1]}
	data.forms["acc|s"] = g == "n" and {args[1]} or {stem .. "an"}
	data.forms["gen|s"] = {stem .. "ini"}
	data.forms["dat|s"] = {stem .. "ini"}
	data.forms["ins|s"] = {stem .. "ini"}
	
	data.forms["nom|p"] = g == "n" and {stem .. "ōn"} or {stem .. "an"}
	data.forms["acc|p"] = g == "n" and {stem .. "ōn"} or {stem .. "an"}
	data.forms["gen|p"] = {stem .. "anō"}
	data.forms["dat|p"] = {stem .. "um"}
	data.forms["ins|p"] = {stem .. "um"}

	postprocess(args, data)
	return make_table(data)
end

function export.cons(frame)
	local params = {
		[1] = {default = mw.title.getCurrentTitle().nsText == "Template" and "{{{1}}}" or mw.title.getCurrentTitle().subpageText},
		
		["n"] = {},
	}

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

	local data = {
		forms = {},
		info = "輔音詞幹",
		categories = {lang:getCanonicalName() .. "輔音詞幹名詞"},
	}

	data.forms["nom|s"] = {args[1]}
	data.forms["acc|s"] = {args[1] .. "u"}
	data.forms["gen|s"] = {args[1] .. "i"}
	data.forms["dat|s"] = {args[1] .. "i"}
	data.forms["ins|s"] = {args[1] .. "i"}
	
	data.forms["nom|p"] = {args[1] .. "i"}
	data.forms["acc|p"] = {args[1] .. "i"}
	data.forms["gen|p"] = {args[1] .. "ō"}
	data.forms["dat|p"] = {args[1] .. "um"}
	data.forms["ins|p"] = {args[1] .. "um"}

	postprocess(args, data)
	return make_table(data)
end

function export.i(frame)
	local params = {
		[1] = {default = mw.title.getCurrentTitle().nsText == "Template" and "{{{1}}}i" or mw.title.getCurrentTitle().subpageText},

		["j"] = {default = mw.title.getCurrentTitle().nsText == "Template" and "ij" or nil},
		["n"] = {},
	}

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

	local data = {
		forms = {},
		info = nil,
		categories = {},
	}

	local stem, suffix = mw.ustring.match(args[1], "^(.-)(i)$")
	local stem_j
	
	if suffix == "i" then
		if (args["j"] or detect_j(stem)) == "ij" then
			stem_j = stem .. "ij"
		else
			stem_j = geminate(stem) .. "j"
		end
	else
		error("i-stems must end in -i")
	end
	
	data.info = "''i''-詞幹"
	table.insert(data.categories, lang:getCanonicalName() .. "i-詞幹名詞")
	
	data.forms["nom|s"] = {args[1]}
	data.forms["acc|s"] = {args[1]}
	data.forms["gen|s"] = {stem .. "ī"}
	data.forms["dat|s"] = {stem .. "ī"}
	data.forms["ins|s"] = {stem .. "ī"}
	
	data.forms["nom|p"] = {stem .. "ī"}
	data.forms["acc|p"] = {stem .. "ī"}
	data.forms["gen|p"] = {stem_j .. "ō"}
	data.forms["dat|p"] = {stem .. "im"}
	data.forms["ins|p"] = {stem .. "im"}

	postprocess(args, data)
	return make_table(data)
end

export["in"] = function(frame)
	local params = {
		[1] = {default = mw.title.getCurrentTitle().nsText == "Template" and "{{{1}}}ī" or mw.title.getCurrentTitle().subpageText},

		["n"] = {},
	}
	
	local args = require("Module:parameters").process(frame:getParent().args, params)

	local data = {
		forms = {},
		info = "''īn''-詞幹",
		categories = {lang:getCanonicalName() .. "īn-詞幹名詞"},
	}

	local stem, suffix = mw.ustring.match(args[1], "^(.-)(ī)$")

	if suffix ~= "ī" then
		error("īn-stems must end in -ī")
	end
	
	data.forms["nom|s"] = {args[1]}
	data.forms["acc|s"] = {stem .. "īn"}
	data.forms["gen|s"] = {stem .. "īn"}
	data.forms["dat|s"] = {stem .. "īn"}
	data.forms["ins|s"] = {stem .. "īn"}

	postprocess(args, data)
	return make_table(data)
end

function export.o(frame)
	local params = {
		[1] = {default = mw.title.getCurrentTitle().nsText == "Template" and "{{{1}}}u" or mw.title.getCurrentTitle().subpageText},

		["j"] = {},
		["n"] = {},
		["w"] = {type = "boolean"},
	}

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

	local data = {
		forms = {},
		info = nil,
		categories = {},
	}

	local stem, suffix = mw.ustring.match(args[1], "^(.-)([iu])$")
	local stem_u

	if suffix == "i" then
		if (args["j"] or detect_j(stem)) == "ij" then
			stem = stem .. "ij"
		else
			stem = geminate(stem) .. "j"
		end

		data.info = "''ī''/''jō''-詞幹"
		table.insert(data.categories, lang:getCanonicalName() .. "ī/jō-詞幹名詞")
	elseif suffix == "u" then
		if args["w"] then
			stem_u = stem
			stem = stem .. "w"
			data.info = "''wō''-詞幹"
			table.insert(data.categories, lang:getCanonicalName() .. "wō-詞幹名詞")
		else
			data.info = "''ō''-詞幹"
			table.insert(data.categories, lang:getCanonicalName() .. "ō-詞幹名詞")
		end
	else
		error("ō-stems must end in -i or -u")
	end

	stem_u = stem_u or stem

	data.forms["nom|s"] = {args[1]}
	data.forms["acc|s"] = {stem .. "ā"}
	data.forms["gen|s"] = {stem .. "ā"}
	data.forms["dat|s"] = {stem .. "ē"}
	data.forms["ins|s"] = {stem_u .. "u"}
	
	data.forms["nom|p"] = {stem .. "ō"}
	data.forms["acc|p"] = {stem .. "ā"}
	data.forms["gen|p"] = {stem .. "ō"}
	data.forms["dat|p"] = {stem .. "ōm"}
	data.forms["ins|p"] = {stem .. "ōm"}

	postprocess(args, data)
	return make_table(data)
end

function export.on(frame)
	local params = {
		[1] = {default = mw.title.getCurrentTitle().nsText == "Template" and "{{{1}}}ā" or mw.title.getCurrentTitle().subpageText},

		["n"] = {},
	}
	
	local args = require("Module:parameters").process(frame:getParent().args, params)

	local data = {
		forms = {},
		info = "''ōn''-詞幹",
		categories = {lang:getCanonicalName() .. "ōn-詞幹名詞"},
	}

	local stem, suffix = mw.ustring.match(args[1], "^(.-)(ā)$")

	if suffix ~= "ā" then
		error("ōn-stems must end in -ā")
	end
	
	data.forms["nom|s"] = {args[1]}
	data.forms["acc|s"] = {stem .. "ōn"}
	data.forms["gen|s"] = {stem .. "ōn"}
	data.forms["dat|s"] = {stem .. "ōn"}
	data.forms["ins|s"] = {stem .. "ōn"}
	
	data.forms["nom|p"] = {stem .. "ōn"}
	data.forms["acc|p"] = {stem .. "ōn"}
	data.forms["gen|p"] = {stem .. "ōnō"}
	data.forms["dat|p"] = {stem .. "ōm"}
	data.forms["ins|p"] = {stem .. "ōm"}

	postprocess(args, data)
	return make_table(data)
end

function export.u(frame)
	local params = {
		[1] = {default = mw.title.getCurrentTitle().nsText == "Template" and "{{{1}}}u" or mw.title.getCurrentTitle().subpageText},

		["n"] = {},
	}

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

	local data = {
		forms = {},
		info = nil,
		categories = {},
	}

	local stem, suffix = mw.ustring.match(args[1], "^(.-)(u)$")

	if suffix ~= "u" then
		error("u-stems must end in -u")
	end
	
	data.info = "''u''-詞幹"
	table.insert(data.categories, lang:getCanonicalName() .. "u-詞幹名詞")
	
	data.forms["nom|s"] = {args[1]}
	data.forms["acc|s"] = {args[1]}
	data.forms["gen|s"] = {stem .. "ō"}
	data.forms["dat|s"] = {stem .. "iwi", stem .. "ō"}
	data.forms["ins|s"] = {stem .. "u"}

	data.forms["nom|p"] = {stem .. "iwi", stem .. "ō"}
	data.forms["acc|p"] = {stem .. "ū"}
	data.forms["gen|p"] = {stem .. "iwō"}
	data.forms["dat|p"] = {stem .. "um"}
	data.forms["ins|p"] = {stem .. "um"}

	postprocess(args, data)
	return make_table(data)
end

function export.z(frame)
	local params = {
		[1] = {default = mw.title.getCurrentTitle().nsText == "Template" and "{{{1}}}" or mw.title.getCurrentTitle().subpageText},

		["n"] = {},
	}

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

	local data = {
		forms = {},
		info = "''z''-詞幹",
		categories = {lang:getCanonicalName() .. "z-詞幹名詞"},
	}
	
	local stem_i = mw.ustring.gsub(args[1], "e(u?[bdfghklmnprʀstþw]*)$", "i%1")

	data.forms["nom|s"] = {args[1]}
	data.forms["acc|s"] = {args[1]}
	data.forms["gen|s"] = {stem_i .. "iʀi"}
	data.forms["dat|s"] = {stem_i .. "iʀi"}
	data.forms["ins|s"] = {stem_i .. "iʀi"}
	
	data.forms["nom|p"] = {stem_i .. "iʀu"}
	data.forms["acc|p"] = {stem_i .. "iʀu"}
	data.forms["gen|p"] = {stem_i .. "iʀō"}
	data.forms["dat|p"] = {stem_i .. "iʀum"}
	data.forms["ins|p"] = {stem_i .. "iʀum"}

	postprocess(args, data)
	return make_table(data)
end

function postprocess(args, data)
	data.n = args["n"]
	
	if args["n"] == "p" then
		table.insert(data.categories, lang:getCanonicalName() .. "唯複名詞")
	elseif args["n"] == "s" then
		table.insert(data.categories, lang:getCanonicalName() .. "唯單名詞")
	elseif args["n"] then
		error("args= must be \"s\" or \"p\".")
	end

	for key, form in pairs(data.forms) do
		-- Do not show singular or plural forms for nominals that don't have them
		if (args["n"] == "p" and key:find("|s$")) or (args["n"] == "s" and key:find("|p$")) then
			form = nil
		end

		data.forms[key] = form
	end
end

-- Make the table
function make_table(data)
	local function repl(param)
		if param == "info" then
			return mw.getContentLanguage():ucfirst(data.info or "")
		end
		
		local forms = data.forms[param]
		
		if not forms then
			return "—"
		end
		
		local ret = {}
		
		for key, subform in ipairs(forms) do
			table.insert(ret, require("Module:links").full_link({lang = lang, alt = "*" .. subform}))
		end
		
		return table.concat(ret, ", ")
	end
	
	local wikicode = {}
	table.insert(wikicode, [=[
{| class="inflection-table vsSwitcher" data-toggle-category="inflection" style="border: solid 1px #CCCCCC;"
|- style="background: #CCCCCC; text-align: left;"
! class="vsToggleElement" colspan="3" | {{{info}}}
|- class="vsShow"
! style="width: 9em;" |
! style="width: 15em; background: #DDDDDD;" colspan="2" | 單數
|- class="vsShow"
! style="background: #EEEEEE" | 主格
| colspan="2" | {{{nom|s}}}
|- class="vsShow"
! style="background: #EEEEEE" | 屬格
| colspan="2" | {{{gen|s}}}
|- class="vsHide"
| style="width: 9em;" |
! style="width: 15em; background: #DDDDDD;" | 單數
! style="width: 15em; background: #DDDDDD;" | 複數
|- class="vsHide"
! style="background: #EEEEEE" | 主格
| {{{nom|s}}}
| {{{nom|p}}}
|- class="vsHide"
! style="background: #EEEEEE" | 賓格
| {{{acc|s}}}
| {{{acc|p}}}
|- class="vsHide"
! style="background: #EEEEEE" | 屬格
| {{{gen|s}}}
| {{{gen|p}}}
|- class="vsHide"
! style="background: #EEEEEE" | 與格
| {{{dat|s}}}
| {{{dat|p}}}
|- class="vsHide"
! style="background: #EEEEEE" | 工具格
| {{{ins|s}}}
| {{{ins|p}}}
|}]=])

	return mw.ustring.gsub(table.concat(wikicode), "{{{([#!]?[a-z0-9|]+)}}}", repl) .. require("Module:utilities").format_categories(data.categories, lang)
end

return export