local export = {}

local pos_functions = {}
local rfind = mw.ustring.find
local rmatch = mw.ustring.match
local rsubn = mw.ustring.gsub
local rsplit = mw.text.split

local lang = require("Module:languages").getByCode("az")
local m_common = require("Module:az-common")

local function is_not_empty(term) return term ~= nil or term ~= '' end

local suffix_categories = {["adjectives"] = true, ["Danh từ"] = true}

-- version of rsubn() that discards all but the first return value
local function rsub(term, foo, bar)
	local retval = rsubn(term, foo, bar)
	return retval
end

local function track(page)
	require("Module:debug").track("az-headword/" .. page)
	return true
end

local no_split_words = {["bə's"] = true}

local function add_space_word_links(space_word, split_dash)
	local space_word_no_punct, punct = rmatch(space_word, "^(.*)([,;:?!])$")
	space_word_no_punct = space_word_no_punct or space_word
	punct = punct or ""
	local words
	-- don’t split prefixes and suffixes
	if not split_dash or rfind(space_word_no_punct, "^%-") or
		rfind(space_word_no_punct, "%-$") then
		words = {space_word_no_punct}
	else
		words = rsplit(space_word_no_punct, "%-")
	end
	local linked_words = {}
	for _, word in ipairs(words) do
		if not no_split_words[word] and rfind(word, "'") then
			word = rsub(word, "([^']+')", "[[%1]]")
			word = rsub(word, "%]([^%[%]]*)$", "][[%1]]")
		else
			word = "[[" .. word .. "]]"
		end
		table.insert(linked_words, word)
	end
	return table.concat(linked_words, "-") .. punct
end

local function add_lemma_links(lemma, split_dash)
	if not rfind(lemma, " ") then split_dash = true end
	local words = rsplit(lemma, " ")
	local linked_words = {}
	for _, word in ipairs(words) do
		table.insert(linked_words, add_space_word_links(word, split_dash))
	end
	local retval = table.concat(linked_words, " ")
	-- If we ended up with a single link consisting of the entire lemma,
	-- remove the link.
	local unlinked_retval = rmatch(retval, "^%[%[([^%[%]]*)%]%]$")
	return unlinked_retval or retval
end

-- The main entry point.
-- This is the only function that can be invoked from a template.
function export.show(frame)
	local PAGENAME = mw.title.getCurrentTitle().text

	local poscat = frame.args[1] or error(
					   "Part of speech has not been specified. Please pass parameter 1 to the module invocation.")

	local params = {
		["head"] = {list = true},
		["suff"] = {type = "boolean"},
		["splitdash"] = {alias_of = "splithyph", type = "boolean"},
		["splithyph"] = {type = "boolean"},
		["nolinkhead"] = {type = "boolean"}
	}

	if rfind(PAGENAME, " ") then track("space") end

	if pos_functions[poscat] then
		for key, val in pairs(pos_functions[poscat].params) do
			params[key] = val
		end
	end

	local parargs = frame:getParent().args
	if parargs.splitdash then track("splitdash") end
	local args = require("Module:parameters").process(parargs, params)

	local heads = args["head"]
	if pos_functions[poscat] and pos_functions[poscat].param1_is_head and
		args[1] then table.insert(heads, 1, args[1]) end
	if args.nolinkhead then
		if #heads == 0 then heads = {PAGENAME} end
	else
		local auto_linked_head = add_lemma_links(PAGENAME, args["splithyph"])
		if #heads == 0 then
			heads = {auto_linked_head}
		else
			for _, head in ipairs(heads) do
				if head == auto_linked_head then
					track("redundant-head")
				end
			end
		end
	end

	local data = {
		lang = lang,
		pos_category = poscat,
		categories = {},
		heads = heads,
		genders = {},
		inflections = {},
		no_redundant_head_cat = #args["head"] == 0,
	}

	if args["suff"] then
		data.pos_category = "suffixes"

		if suffix_categories[poscat] then
			local singular_poscat = poscat:gsub("s$", "")
			table.insert(data.categories, lang:getCanonicalName() .. " " ..
							 singular_poscat .. "-forming suffixes")
		else
			error("No category exists for suffixes forming " .. poscat .. ".")
		end
	end

	if pos_functions[poscat] then pos_functions[poscat].func(args, data) end

	return require("Module:headword").full_headword(data)
end

local function do_adjective(pos)
	return {
		params = {
			[1] = {} -- hyphen (-) if incomparable, intensive form otherwise
		},
		func = function(args, data)
			local PAGENAME = mw.title.getCurrentTitle().text
			local script = lang:findBestScript(PAGENAME):getCode()
			local function comp()
				if script == "Latn" then
					return "[[daha]] "
				elseif script == "Cyrl" then
					return "[[даһа]] "
				end
			end
			local function sup()
				if script == "Latn" then
					return "[[ən]] "
				elseif script == "Cyrl" then
					return "[[ән]] "
				end
			end

			if args[1] == "-" then
				table.insert(data.inflections, {label = "not comparable"})
			else
				table.insert(data.inflections,
							 {label = "comparative", comp() .. PAGENAME})
				table.insert(data.inflections,
							 {label = "superlative", sup() .. PAGENAME})
				if args[1] then
					table.insert(data.inflections,
								 {label = "intensive", args[1]})
				end
			end
		end
	}
end

local function get_noun_pos(is_proper)
	return {
		params = {
			[1] = {},
			[2] = {},
			["stem"] = {},
			["broken"] = {},
			["broken-v"] = {},
			["nb"] = {},
			["sing"] = {}
		},
		func = function(args, data)
			local PAGENAME = mw.title.getCurrentTitle().text
			local script = lang:findBestScript(PAGENAME):getCode()

			local args1 = is_not_empty(args[1]) and args[1] or ""
			local args2 = is_not_empty(args[2]) and args[2] or ""
			local stem = args["stem"]
			local nb = args["nb"]
			local sing = args["sing"]
			local broken = args["broken"]

			if args1 == "" and args2 == "" then
				args1, args2 = m_common.getType(PAGENAME)
			elseif args1 == "" then
				track("args2 was overridden")
				args1, _ = m_common.getType(PAGENAME)
			elseif args2 == "" then
				track("args1 was overridden")
				_, args2 = m_common.getType(PAGENAME)
			else
				track("args1 and args2 were overridden")
			end

			local function stemforacc()
				if script == "Latn" then
					if args2 == "q" then
						return mw.ustring.sub(PAGENAME, 1, -2) .. 'ğ'
					elseif args2 == "k" then
						return mw.ustring.sub(PAGENAME, 1, -2) .. 'y'
					else
						return PAGENAME
					end
				elseif script == "Cyrl" then
					if args2 == "г" then
						return mw.ustring.sub(PAGENAME, 1, -2) .. 'ғ'
					elseif args2 == "к" then
						return mw.ustring.sub(PAGENAME, 1, -2) .. 'ј'
					else
						return PAGENAME
					end
				end
			end
			local function stemforpl()
				if script == "Latn" then
					if args2 == "cc" then
						return mw.ustring.sub(PAGENAME, 1, -2)
					else
						return PAGENAME
					end
				elseif script == "Cyrl" then
					if args2 == "cc" then
						return mw.ustring.sub(PAGENAME, 1, -2)
					else
						return PAGENAME
					end
				end
			end
			local function azv1()
				if script == "Latn" then
					if rfind(args1, "[əeiöü]") then
						return "i"
					else
						return "ı"
					end
				elseif script == "Cyrl" then
					if rfind(args1, "[әеиөү]") then
						return "и"
					else
						return "ы"
					end
				end
			end
			local function azv2()
				if script == "Latn" then
					if rfind(args1, "[əeiöü]") then
						return "ə"
					else
						return "a"
					end
				elseif script == "Cyrl" then
					if rfind(args1, "[әеиөү]") then
						return "ә"
					else
						return "а"
					end
				end
			end
			local function azv3()
				if script == "Latn" then
					if rfind(args1, "[əei]") then
						return "i"
					elseif rfind(args1, "[öü]") then
						return "ü"
					elseif rfind(args1, "[aı]") then
						return "ı"
					else
						return "u"
					end
				elseif script == "Cyrl" then
					if rfind(args1, "[әеи]") then
						return "и"
					elseif rfind(args1, "[өү]") then
						return "ү"
					elseif rfind(args1, "[аы]") then
						return "ы"
					else
						return "у"
					end
				end
			end
			local function n()
				if script == "Latn" then
					return "n"
				elseif script == "Cyrl" then
					return "н"
				end
			end
			local function l()
				if script == "Latn" then
					return "l"
				elseif script == "Cyrl" then
					return "л"
				end
			end
			local function r()
				if script == "Latn" then
					return "r"
				elseif script == "Cyrl" then
					return "р"
				end
			end

			if args2 == "c" or args2 == "cc" or args2 == "q" or args2 == "k" then
				if stem then
					if sing == "no" then
						if nb == "no" then
							if broken then
								table.insert(data.genders, {"p"})
							else
								table.insert("?")
							end
						else
							table.insert(data.genders, {"p"})
							if broken then
								table.insert(data.inflections, {
									label = "broken plural",
									accel = {form = "nom|broken|plural"},
									broken
								})
							end
						end
					else
						if nb == "no" then
							table.insert(data.inflections, {
								label = "[[accusative|acc.]] xác định",
								accel = {form = "def|acc|s"},
								stem .. azv3()
							})
							if broken then
								table.insert(data.inflections, {
									label = "broken plural",
									accel = {form = "nom|broken|plural"},
									broken
								})
							end
						else
							if broken then
								table.insert(data.inflections, {
									label = "[[accusative|acc.]] xác định",
									accel = {form = "def|acc|s"},
									stem .. azv3()
								})
								table.insert(data.inflections, {
									label = "sound plural",
									accel = {form = "nom|sound|p"},
									PAGENAME .. l() .. azv2() .. r()
								})
								table.insert(data.inflections, {
									label = "broken plural",
									accel = {form = "nom|broken|p"},
									broken
								})
							else
								table.insert(data.inflections, {
									label = "[[accusative|acc.]] xác định",
									accel = {form = "def|acc|s"},
									stem .. azv3()
								})
								table.insert(data.inflections, {
									label = "số nhiều",
									accel = {form = "nom|p"},
									PAGENAME .. l() .. azv2() .. r()
								})
							end
						end
					end
				else
					if sing == "no" then
						if nb == "no" then
							if broken then
								table.insert(data.genders, {"p"})
							else
								table.insert("?")
							end
						else
							table.insert(data.genders, {"p"})
							if broken then
								table.insert(data.inflections, {
									label = "broken plural",
									accel = {form = "nom|broken|plural"},
									broken
								})
							end
						end
					else
						if nb == "no" then
							table.insert(data.inflections, {
								label = "[[accusative|acc.]] xác định",
								accel = {form = "def|acc|s"},
								stemforacc() .. azv3()
							})
							if broken then
								table.insert(data.inflections, {
									label = "broken plural",
									accel = {form = "nom|broken|plural"},
									broken
								})
							end
						else
							if broken then
								table.insert(data.inflections, {
									label = "[[accusative|acc.]] xác định",
									accel = {form = "def|acc|s"},
									stemforacc() .. azv3()
								})
								table.insert(data.inflections, {
									label = "sound plural",
									accel = {form = "nom|sound|p"},
									stemforpl() .. l() .. azv2() .. r()
								})
								table.insert(data.inflections, {
									label = "broken plural",
									accel = {form = "nom|broken|p"},
									broken
								})
							else
								table.insert(data.inflections, {
									label = "[[accusative|acc.]] xác định",
									accel = {form = "def|acc|s"},
									stemforacc() .. azv3()
								})
								table.insert(data.inflections, {
									label = "số nhiều",
									accel = {form = "nom|p"},
									stemforpl() .. l() .. azv2() .. r()
								})
							end
						end
					end
				end
			else
				if stem then
					if sing == "no" then
						if nb == "no" then
							if broken then
								table.insert(data.genders, {"p"})
							else
								table.insert("?")
							end
						else
							table.insert(data.genders, {"p"})
							if broken then
								table.insert(data.inflections, {
									label = "broken plural",
									accel = {form = "nom|broken|plural"},
									broken
								})
							end
						end
					else
						if nb == "no" then
							table.insert(data.inflections, {
								label = "[[accusative|acc.]] xác định",
								accel = {form = "def|acc|s"},
								stem .. azv3()
							})
							if broken then
								table.insert(data.inflections, {
									label = "broken plural",
									accel = {form = "nom|broken|plural"},
									broken
								})
							end
						else
							if broken then
								table.insert(data.inflections, {
									label = "[[accusative|acc.]] xác định",
									accel = {form = "def|acc|s"},
									stem .. azv3()
								})
								table.insert(data.inflections, {
									label = "sound plural",
									accel = {form = "nom|sound|p"},
									PAGENAME .. l() .. azv2() .. r()
								})
								table.insert(data.inflections, {
									label = "broken plural",
									accel = {form = "nom|broken|p"},
									broken
								})
							else
								table.insert(data.inflections, {
									label = "[[accusative|acc.]] xác định",
									accel = {form = "def|acc|s"},
									stem .. azv3()
								})
								table.insert(data.inflections, {
									label = "số nhiều",
									accel = {form = "nom|p"},
									PAGENAME .. l() .. azv2() .. r()
								})
							end
						end
					end
				else
					if sing == "no" then
						if nb == "no" then
							if broken then
								table.insert(data.genders, {"p"})
							else
								table.insert("?")
							end
						else
							table.insert(data.genders, {"p"})
							if broken then
								table.insert(data.inflections, {
									label = "broken plural",
									accel = {form = "nom|broken|plural"},
									broken
								})
							end
						end
					else
						if nb == "no" then
							table.insert(data.inflections, {
								label = "[[accusative|acc.]] xác định",
								accel = {form = "def|acc|s"},
								PAGENAME .. n() .. azv3()
							})
							if broken then
								table.insert(data.inflections, {
									label = "broken plural",
									accel = {form = "nom|broken|plural"},
									broken
								})
							end
						else
							if broken then
								table.insert(data.inflections, {
									label = "[[accusative|acc.]] xác định",
									accel = {form = "def|acc|s"},
									PAGENAME .. n() .. azv3()
								})
								table.insert(data.inflections, {
									label = "sound plural",
									accel = {form = "nom|sound|p"},
									PAGENAME .. l() .. azv2() .. r()
								})
								table.insert(data.inflections, {
									label = "broken plural",
									accel = {form = "nom|broken|p"},
									broken
								})
							else
								table.insert(data.inflections, {
									label = "[[accusative|acc.]] xác định",
									accel = {form = "def|acc|s"},
									PAGENAME .. n() .. azv3()
								})
								table.insert(data.inflections, {
									label = "số nhiều",
									accel = {form = "nom|p"},
									PAGENAME .. l() .. azv2() .. r()
								})
							end
						end
					end
				end
			end
		end
	}
end

pos_functions["Danh từ"] = get_noun_pos(false)

pos_functions["proper nouns"] = get_noun_pos(true)

pos_functions["adjectives"] = do_adjective("adjectives")

return export