local export = {}
local m_string_utils = require("Module:string utilities")

local find = m_string_utils.find
local match = m_string_utils.match
local split = mw.text.split
local gsplit = mw.text.gsplit
local gsub = m_string_utils.gsub

local initial_ipa = {
	["b"] = "p", ["p"] = "pʰ", ["m"] = "m", ["bh"] = "b",
	["d"] = "t", ["t"] = "tʰ", ["n"] = "n", ["l"] = "l",
	["g"] = "k", ["k"] = "kʰ", ["ng"] = "ŋ", ["h"] = "h",
	["j"] = "t͡s", ["q"] = "t͡sʰ", ["x"] = "s", ["y"] = "z",
	["z"] = "t͡s", ["c"] = "t͡sʰ", ["s"] = "s",
	[""] = ""
}

local final_ipa = {
	["i"] = "i", ["u"] = "u",
	["a"] = "a", ["ia"] = "ia", ["ua"] = "ua",
	["o"] = "ɔ", ["io"] = "iɔ",
	["e"] = "ɛ", ["ie"] = "iɛ", ["ue"] = "uɛ",
	["ai"] = "ai", ["uai"] = "uai",
	["ao"] = "au", ["iao"] = "iau",
	["eu"] = "ɛu", ["iu"] = "iu",
	["oi"] = "ɔi", ["ui"] = "ui",
	["am"] = "am", ["iam"] = "iam", ["m"] = "m̩",
	["em"] = "em", ["im"] = "im",
	["ang"] = "aŋ", ["iang"] = "iaŋ", ["uang"] = "uaŋ",
	["eng"] = "eŋ", ["ieng"] = "ieŋ", ["ng"] = "ŋ̍",
	["ong"] = "ɔŋ", ["iong"] = "iɔŋ",
	["ing"] = "iŋ", ["ung"] = "uŋ",
	["ab"] = "ap̚", ["iab"] = "iap̚",
	["eb"] = "ep̚", ["ib"] = "ip̚",
	["ag"] = "ak̚", ["iag"] = "iak̚", ["uag"] = "uak̚",
	["eg"] = "ek̚", ["ieg"] = "iek̚", ["ueg"] = "uek̚",
	["ig"] = "ik̚", ["ug"] = "uk̚",
	["og"] = "ɔk̚", ["iog"] = "iɔk̚",
}

local tone_chao = {
	["1"] = "³⁵", ["2"] = "³¹", ["3"] = "²¹", ["4"] = "⁵",
	["5"] = "²²", ["6"] = "³³", ["7"] = "⁵⁵", ["8"] = "²"
}

-- find the sandhied tone of the first syllable in a two-syllable word
-- returns nil if the tone of the first syllable does not change
local function tone_sandhi(tone1, tone2)
	if tone1 == "1" then
		return "6"
	elseif (tone1 == "2" and match(tone2, "[1256]")) or (tone1 == "3" and match(tone2, "[123568]")) then
		return "7"
	end
end

-- convert Leizhounese Pinyin to IPA
function export.ipa(text)
	if type(text) == "table" then
		text = text.args[1]
	end
	
	local result = {}
	
	for word in gsplit(text, "/") do
		local syllables = split(word, " ")
		local initial, final, tone, block, sandhi, ipa = {}, {}, {}, {}, {}, {}
		for i, syllable in ipairs(syllables) do
			initial[i], final[i], tone[i], block[i] = match(syllable, "^([bpmdtnlgkhjqxyzcs]?[hg]?)([aeiou][aeioumnbg]?[iomnbg]?g?)([1-8])(#?)$")
		
			-- check z/c/s vs. j/q/x
			if (find(initial[i], "^[zcs]$") and find(final[i], "^i")) or (find(initial[i], "^[jqx]$") and find(final[i], "^[aeou]")) then
				error("Invalid Leizhou pinyin input \"" .. syllable .. "\": initial " .. initial[i] .. " cannot go with final " .. final[i] .. ".")
			end	
			
			-- check checked tones
			if (find(final[i], "[^n][bdg]$") and find(tone[i], "^[^48]$")) or ((find(final[i], "[^bdg]$") or find(final[i], "ng$")) and find(tone[i], "^[48]$")) then
				error("Invalid Leizhou pinyin input \"" .. syllable .. "\": final " .. final[i] .. " cannot go with tone " .. tone[i] .. ".")
			end
		end
		
		for i=1,#syllables,1 do
			if i+1 <= #syllables and block[i] ~= "#" then
				sandhi[i] = tone_sandhi(tone[i], tone[i+1])
			end
		end
		
		for i=1,#syllables,1 do
			actual_tone = tone_chao[tone[i]] .. (sandhi[i] and "⁻" .. tone_chao[sandhi[i]] or "")
			ipa[i] = initial_ipa[initial[i]] .. final_ipa[final[i]] .. actual_tone
		end
		table.insert(result, table.concat(ipa, " "))
	end
	
	return "/" .. table.concat(result, "/, /") .. "/"
end

function export.rom(text)
	text = gsub(text, "/", " / ")
	text = gsub(text, '([1-9-]+)', '<sup>%1</sup>')
	return text
end

return export