local m_links = require("Module:links")
local m_utils = require("Module:utilities")
local lang = require("Module:languages").getByCode("sw")

PAGENAME = mw.title.getCurrentTitle().text or ''
local export = {}

local o_of_reference = {
	"ye", "o", "yo", "lo", "cho", "vyo", "zo", "ko", "po", "mo"
}

local obj_infixes = {
	"ni", "ku", "m", "tu", "wa", "ji", "u", "i", "li", "ya", "ki", "vi", "zi", "pa", "mu"
}

local irreg_kw_inf = {
	['isha'] = true,
	['enda'] = true,
	['anza'] = true,
}

local subj_list = {
	"1s", "2s", "3s", "1p", "2p", "3p",
	"3c", "4c", "5c", "6c", "7c", "8c", "9c", "10c", "11c", "15c", "16c", "18c",
}

local subjects = {
	["p"] = {
		["1s"] = {"ni"},
		["2s"] = {"u"},
		["3s"] = {"a"},
		["1p"] = {"tu"},
		["2p"] = {"m"},
		["3p"] = {"wa"},
		["3c"] = {"u"},
		["4c"] = {"i"},
		["5c"] = {"li"},
		["6c"] = {"ya"},
		["7c"] = {"ki"},
		["8c"] = {"vi"},
		["9c"] = {"i"},
		["10c"] = {"zi"},
		["11c"] = {"u"},
		["15c"] = {"ku"},
		["16c"] = {"pa"},
		["18c"] = {"mu"},
	},
	["n"] = {
		["1s"] = {"si"},
		["2s"] = {"hu"},
		["3s"] = {"ha"},
		["1p"] = {"hatu"},
		["2p"] = {"ham"},
		["3p"] = {"hawa"},
		["3c"] = {"hau"},
		["4c"] = {"hai"},
		["5c"] = {"hali"},
		["6c"] = {"haya"},
		["7c"] = {"haki"},
		["8c"] = {"havi"},
		["9c"] = {"hai"},
		["10c"] = {"hazi"},
		["11c"] = {"hau"},
		["15c"] = {"haku"},
		["16c"] = {"hapa"},
		["18c"] = {"hamu"},
	},
	["cont"] = {
		["1s"] = {"n"},
		["2s"] = {"w"},
		["3s"] = {""},
		["1p"] = {"tw"},
		["2p"] = {"mw"},
		["3p"] = {"w"},
		["3c"] = {"w"},
		["4c"] = {"y"},
		["5c"] = {"l"},
		["6c"] = {"y"},
		["7c"] = {"ch"},
		["8c"] = {"vy"},
		["9c"] = {"y"},
		["10c"] = {"z"},
		["11c"] = {"w"},
		["15c"] = {"kw"},
		["16c"] = {"p"},
		["18c"] = {"mw"},
	},
}
subjects.r = subjects.p

local tam = {
	["past"] = {
		["p"] = {{
			"li",
			alt = {
				["1s"] = {"ni", "na"},
				["2s"] = {"u", "wa"},
				["1p"] = {"tu", "twa"},
				["2p"] = {"m", "mwa"}
			},
			mono = true,
		}},
		["r"] = {{
			"lio",
			alt = {
				["1s"] = {"ni", "na"},
				["2s"] = {"u", "wa"},
				["1p"] = {"tu", "twa"},
				["2p"] = {"m", "mwa"}
			},
			mono = true,
		}},
		["n"] = {{"ku"}},
	},
	["pres"] = {
		["p"] = {{
			"na",
			alt = {
				["1s"] = {"ni", ""}
			},
			mono = true,
		}},
		["r"] = {{
			"nao",
			alt = {
				["1s"] = {"ni", ""}
			},
			mono = true,
		}},
		["n"] = {{
			"",
			final = "i",
			mono = true,
		}},
	},
	["fut"] = {
		["p"] = {{
			"ta",
			mono = true,
		}},
		["r"] = {{
			"takao",
			mono = true,
		}},
		["n"] = {{
			"ta",
			mono = true,
		}},
	},
	["cond_pres"] = {
		["p"] = {{
			"nge",
			mono = true,
		}},
		["n"] = {
			{
				"singe",
				alt = subjects.p,
				mono = true,
			},
			{
				"nge",
				alt = subjects.n,
				mono = true,
			}
		}
	},
	["cond_past"] = {
		["p"] = {{
			"ngali",
			mono = true,
		}},
		["n"] = {
			{
				"singali",
				alt = subjects.p,
				mono = true,
			},
			{
				"ngali",
				alt = subjects.n,
				mono = true,
			}
		}
	},
	["cond_cont"] = {
		["p"] = {{
			"ngeli",
			mono = true,
		}},
	},
	["perf"] = {
		["p"] = {{
			"me",
			mono = true,
		}},
	},
	["alr"] = {
		["p"] = {{
			"mesha",
			mono = true,
		}},
	},
	["ifw"] = {
		["p"] = {{"ki"}},
	},
	["cons"] = {
		["p"] = {{"ka"}},
	},
	["gnom"] = {
		["p"] = {{
			"a",
			alt = subjects.cont,
		}},
	},
	["ny"] = {
		["n"] = {{"ja"}},
	},
	["ifn"] = {
		["n"] = {{
			"sipo",
			alt = subjects.p,
			mono = true,
		}},
	},
	["subj"] = {
		["p"] = {{
			"",
			final = "e"
		}},
		["n"] = {{
			"si",
			final = "e",
			alt = subjects.p,
		}},
	},
	["rel"] = {
		["p"] = {{
			"",
			final = "ao",
		}},
		["n"] = {{
			"sio",
			alt = subjects.p,
			mono = true,
		}},
	},
}
local tamcopy = tam

function tablelength(T)
  local count = 0
  for _ in pairs(T) do count = count + 1 end
  return count
end

local function get_stem(lemma, args)
	if not mw.ustring.match(lemma, "a$") then
		-- Arabic verb
		return lemma, true, false, {"Swahili verbs in the Arabic conjugation"}
	elseif mw.ustring.match(lemma, "^[^aeiou]+a$") or args.mono ~= nil then
		-- Monosyllabic
		return mw.ustring.gsub(lemma, "^(.*)a$", "%1"), false, true, {"Swahili verbs in the monosyllabic conjugation"}
	else
		-- Normal verbs
		return mw.ustring.gsub(lemma, "^(.*)a$", "%1"), false, false, {}
	end
end

local function link(term, accel_optional)
	if accel_optional then
		return m_links.full_link({lang = lang, term = term, allowSelfLink = false, accel = {form = accel_optional} })
	else
		return m_links.full_link({lang = lang, term = term, allowSelfLink = false})
	end
end

local function user_specified(text)
	if text == '-' then
		return '—'
	else
		local temp = {}
		for i, term in ipairs(mw.text.split(text, '/')) do
			table.insert(temp, link(term))
		end
		return table.concat(temp, '<br/>')
	end
end

local function setDefault (t, d)
	local mt = {__index = function () return d end}
	setmetatable(t, mt)
end

local output_subj_accel = {
	["3c"] = "m-mi|singular",
	["4c"] = "m-mi|plural",
	["5c"] = "ji-ma|singular",
	["6c"] = "ji-ma|plural",
	["7c"] = "ki-vi|singular",
	["8c"] = "ki-vi|plural",
	["9c"] = "n-n|singular",
	["10c"] = "n-n|plural",
	["11c"] = "u-n|singular",
	["15c"] = "ku",
	["16c"] = "pa",
	["18c"] = "mu",
}
setDefault(output_subj_accel, "")

local addition_accel = {
	["3s"] = "m-wa|singular",
	["3p"] = "m-wa|plural",
	["10c"] = "u-n|plural",
	["15c"] = "ku-loc",
}
setDefault(addition_accel, "")

local tampol_accel = {
	["pres-p"] = "|present",
	["pres-n"] = "|present|negative",
	["perf-p"] = "|perfect",
	["gnom-p"] = "|gnomic",
	["subj-p"] = "|subjunctive",
	["subj-n"] = "|subjunctive|negative",
	["past-p"] = "|past",
	["past-n"] = "|past|negative",
	["fut-p"] = "|future",
	["fut-n"] = "|future|negative",
	["cons-p"] = "|consecutive",
	["cond_pres-p"] = "|conditional",
	["ifw-p"] = "|situational",
}
setDefault(tampol_accel, "")

local function make_accel(subj_name, tam, pol)
	output_subj = output_subj_accel[subj_name]
	output_subj = output_subj ~= "" and output_subj or subj_name
	addition = addition_accel[subj_name]
	tampol = tampol_accel[tam .. "-" .. pol]
	accel_keywords = nil
	if tampol ~= "" then
		accel_keywords = "verb:|" .. output_subj .. tampol
		if addition ~= "" then
			accel_keywords = accel_keywords .. "|;|" .. addition .. tampol
		end
	end
	return accel_keywords
end

local function make_forms(args, lemma, stem, arabic, monosyllabic)
	local tag, temp, form, subjs
	local forms = {}
	
	local inf, inf_stem = table.concat{'ku', lemma}, table.concat{'ku', stem}
	if args.inf then
		forms.inf = user_specified(args.inf)
	elseif irreg_kw_inf[lemma] then
		inf, inf_stem = table.concat{'kw', lemma}, table.concat{'kw', stem}
		forms.inf = link(inf)
	else
		forms.inf = link(inf)
	end
	
	if args.inf_n then
		forms.inf_n = user_specified(args.inf_n)
	elseif monosyllabic then
		forms.inf_n = link(table.concat{'kuto', inf})
	else
		forms.inf_n = link(table.concat{'kuto', lemma})
	end
	
	if args.hab then
		forms.hab = user_specified(args.hab)
	else
		forms.hab = link(table.concat{'hu', lemma})
	end
	
	if args.imp_s then
		forms.imp_s = user_specified(args.imp_s)
	elseif arabic then
		forms.imp_s = link(lemma)
	elseif monosyllabic then
		forms.imp_s = link(inf)
	else
		forms.imp_s = link(lemma)
	end
	
	if args.imp_p then
		forms.imp_p = user_specified(args.imp_p)
	elseif arabic then
		forms.imp_p = link(table.concat{lemma, 'ni'})
	elseif monosyllabic then
		forms.imp_p = link(table.concat{inf_stem, 'eni'})
	else
		forms.imp_p = link(table.concat{stem, 'eni'})
	end
	
	forms.title = table.concat{"''-", lemma, "''"}
	
	for _, infix in ipairs(obj_infixes) do
		tagfix = infix
		lemmafix = lemma
		if infix == "m" and string.match(string.sub(lemma, 1, 1), "[aeiou]") then
			infix = "mw"
		end
		forms["inf_obj_" .. tagfix] = 'ku' .. infix .. lemma
		forms["hab_obj_" .. tagfix] = 'hu' .. infix .. lemma
		if infix == "ku" or infix == "wa" then -- -eni/-ni ending
			if string.sub(lemma, -1) == "a" then
				lemmafix = string.reverse(string.gsub(string.reverse(lemma), 'a', 'e', 1))
			end
			forms["inf_obj_" .. tagfix] = forms["inf_obj_" .. tagfix] .. '<br/>' .. 'ku' .. infix .. lemmafix .. 'ni'
			forms["hab_obj_" .. tagfix] = forms["hab_obj_" .. tagfix] .. '<br/>' .. 'hu' .. infix .. lemmafix .. 'ni'
		end
	end
	
	for tam, tam_val in pairs(tam) do
		for pol, pols in pairs(tam_val) do
			for _, subj_name in ipairs(subj_list) do
				tag = table.concat({tam, pol, subj_name}, '_')
				temp = {}
				if args[tag] ~= nil then -- user specified
					forms[tag] = user_specified(args[tag])
				else
					for _, pol_val in ipairs(pols) do
						if pol_val.alt and pol_val.alt[subj_name] then
							subjs = pol_val.alt[subj_name]
						else
							subjs = subjects[pol][subj_name]
						end
						for _, subj in ipairs(subjs) do
							accel_keywords = nil
							form = {}
							-- subject marker
							table.insert(form, subj)
							-- tam
							table.insert(form, pol_val[1])
							-- stem
							if monosyllabic and pol_val.mono and not (pol == 'n' and tam == 'pres') then
								table.insert(form, inf_stem)
							else
								table.insert(form, stem)
							end
							-- suffix
							if arabic then
								table.insert(form, "")
							elseif pol_val.final then
								table.insert(form, pol_val.final)
							else
								table.insert(form, "a")
							end
							if (tam == "past" and pol == "r") or (tam == "pres" and pol == "r") or (tam == "fut" and pol == "r") or (tam == "rel" and pol == "p") or (tam == "rel" and pol == "n") then
								if tam == "rel" and pol == "p" then
									oindex = 4
								else
									oindex = 2
								end
								for _, o in ipairs(o_of_reference) do
									relform = {}
									for k, v in pairs(form) do
    									relform[k] = v
									end
									if tam == "rel" and lemma == "wa" then
										if pol == "p" then
											relform[3] = "li"
											relform[4] = "o"
										end
										if pol == "n" then
											relform[3] = ""
											relform[4] = ""
										end
									end
									relform[oindex] = string.gsub(relform[oindex], "o", o)
									if forms[tag .. "_" .. o] ~= nil then -- handles alt forms "na" vs "nina", etc
										forms[tag .. "_" .. o] = forms[tag .. "_" .. o] .. '<br/>' .. table.concat(relform)
									else
										forms[tag .. "_" .. o] = table.concat(relform) -- link(table.concat(relform))
									end
									if oindex == 2 and string.sub(relform[3], 1, 1) == "i" then -- double i as in "aliyoiita"
										relform[oindex] = string.gsub(relform[oindex], o, o .. "i")
										forms[tag .. "_" .. o] = forms[tag .. "_" .. o] .. '<br/>' .. table.concat(relform) -- link(table.concat(relform))
									end
									if lemma == "wa" and (tam == "rel" or tam == "past" or tam == "fut") then -- special case locative options for -wa
										forms[tag .. "_" .. o] = forms[tag .. "_" .. o] .. '<br/>' .. table.concat(relform) .. 'po'
										forms[tag .. "_" .. o] = forms[tag .. "_" .. o] .. '<br/>' .. table.concat(relform) .. 'ko'
										forms[tag .. "_" .. o] = forms[tag .. "_" .. o] .. '<br/>' .. table.concat(relform) .. 'mo'
									end
								end
							end
							for _, infix in ipairs(obj_infixes) do
								obji = infix
								objform = {}
								for k, v in pairs(form) do
    								objform[k] = v
								end
								if infix == "m" and string.match(string.sub(objform[3], 1, 1), "[aeiou]") then
									infix = "mw"
								end
								objform[2] = objform[2] .. infix
								if forms[tag .. "_" .. obji] ~= nil then -- handles alt forms "na" vs "nina", etc
									forms[tag .. "_" .. obji] = forms[tag .. "_" .. obji] .. '<br/>' .. table.concat(objform)
								else
									forms[tag .. "_" .. obji] = table.concat(objform) -- link(table.concat(objform))
								end
								if infix == "ku" or infix == "wa" then -- -eni/-ni ending
									if string.sub(objform[4], -1) == "a" then
										objform[4] = string.gsub(objform[4], "a", "e")
									end
									objform[4] = objform[4] .. "ni"
									forms[tag .. "_" .. obji] = forms[tag .. "_" .. obji] .. '<br/>' .. table.concat(objform) -- link(table.concat(objform))
								end
							end
							accel_keywords = make_accel(subj_name, tam, pol)
							if accel_keywords == "" then
								table.insert(temp, link(table.concat(form)))
							else
								table.insert(temp, link(table.concat(form), accel_keywords))
							end
						end
					end
					forms[tag] = table.concat(temp, "<br/>")
				end
			end
		end
	end
	return forms
end

function export.show(frame)
	if
		mw.title.getCurrentTitle().nsText == "Template" and
		tablelength(frame:getParent().args) == 0 
	then
		return frame:expandTemplate{title= 'sw-conj/table', args = {}}
	end
	
	local args = frame:getParent().args or {}
	
	local lemma = args[1] or PAGENAME
	local stem, arabic, monosyllabic, cat = get_stem(lemma, args)
	
	return frame:expandTemplate{
		title= 'sw-conj/table',
		args = make_forms(args, lemma, stem, arabic, monosyllabic)
		} .. m_utils.format_categories(cat, lang)
end

function export.show_sandbox(frame)
	if
		mw.title.getCurrentTitle().nsText == "Template" and
		tablelength(frame:getParent().args) == 0 
	then
		return frame:expandTemplate{title= 'sw-conj/table/sandbox', args = {}}
	end
	
	local args = frame:getParent().args or {}
	
	local lemma = args[1] or PAGENAME
	local stem, arabic, monosyllabic, cat = get_stem(lemma, args)
	
	return frame:expandTemplate{
		title= 'sw-conj/table/sandbox',
		args = make_forms(args, lemma, stem, arabic, monosyllabic)
		} .. m_utils.format_categories(cat, lang)
end

function export.show_pres_prn(frame)
	if
		mw.title.getCurrentTitle().nsText == "Template" and
		tablelength(frame:getParent().args) == 0 
	then
		return frame:expandTemplate{title= 'sw-conj/table-pres-prn', args = {}}
	end
	
	local args = frame:getParent().args or {}
	
	local lemma = args[1] or PAGENAME
	local stem, arabic, monosyllabic, cat = get_stem(lemma, args)
	
	return frame:expandTemplate{
		title= 'sw-conj/table-pres-prn',
		args = make_forms(args, lemma, stem, arabic, monosyllabic)
		} .. m_utils.format_categories(cat, lang)
end

function export.show_pres_pn(frame)
	if
		mw.title.getCurrentTitle().nsText == "Template" and
		tablelength(frame:getParent().args) == 0 
	then
		return frame:expandTemplate{title= 'sw-conj/table-pres-pn', args = {}}
	end
	
	local args = frame:getParent().args or {}
	
	local lemma = args[1] or PAGENAME
	local stem, arabic, monosyllabic, cat = get_stem(lemma, args)
	
	return frame:expandTemplate{
		title= 'sw-conj/table-pres-pn',
		args = make_forms(args, lemma, stem, arabic, monosyllabic)
		} .. m_utils.format_categories(cat, lang)
end

function export.show_pres_p(frame)
	if
		mw.title.getCurrentTitle().nsText == "Template" and
		tablelength(frame:getParent().args) == 0 
	then
		return frame:expandTemplate{title= 'sw-conj/table-pres-p', args = {}}
	end
	
	local args = frame:getParent().args or {}
	
	local lemma = args[1] or PAGENAME
	local stem, arabic, monosyllabic, cat = get_stem(lemma, args)
	
	return frame:expandTemplate{
		title= 'sw-conj/table-pres-p',
		args = make_forms(args, lemma, stem, arabic, monosyllabic)
		} .. m_utils.format_categories(cat, lang)
end

return export