local cfg= mw.loadData('Module:Hijri/Configuration')
local core = require 'Module:Hijri/core/ملعب'
--[[ ----------------- I M P O R T --------------]]
gregorian2jd = core.gregorian2jd
jd2hijri = core.jd2hijri
hijri2jd = core.hijri2jd
hijri_days_in_month = core.hijri_days_in_month
hijri_isleap = core.hijri_isleap
hijri_yday = core.hijri_yday
jd2unix = core.jd2unix
unix2jd = core.unix2jd
jd2wday = core.jd2wday
jd2gregorian = core.jd2gregorian
gre_isleap = core.gre_isleap
gre_yday = core.gre_yday
gre_days_in_month = core.gre_days_in_month
jd2julian = core.jd2julian
julian2jd = core.julian2jd
julian_isleap = core.julian_isleap
julian_yday = core.julian_yday
julian_days_in_month = core.julian_days_in_month
gregorian2hijri = core.gregorian2hijri
hijri2gregorian = core.hijri2gregorian
Date = core.Date
hijri_check = core.hijri_check
string = mw.ustring
local str_hijri_mode = select(cfg.hijri_mode + 1, 'hijri_tabular', 'hijri_adjusted_umalqura', 'hijri_umalqura')

--[[---------------------- utilty function ----------------- ]]
local gtonumber = tonumber

local function tonumber(str)
	if not str then
		return nil
	end
	local thenumber = gtonumber(str) or mw.language.getContentLanguage():parseFormattedNumber(str)
	if not thenumber then
		return nil
	end
	return math.floor(thenumber)
end

local function substitute( msg, args )
	return args and mw.message.newRawMessage( msg, args ):plain() or msg;
end

local function error( msg, args )
	return substitute( cfg.presentation.error, substitute( msg, args ) );
end

local function towdigit(number)
	return ((number<10) and '0' or '') .. number
end

local function hijri_month_name(index)
	if cfg.hijri_months and #cfg.hijri_months==12 then
		return cfg.hijri_months[index]
	else
		return mw.message.new('hijri-calendar-m' .. index):plain()
	end
end

local function wday_name(index)
	if cfg.wday_name and #cfg.wday_name==7 then
		return cfg.wday_name[index]
	else
		return mw.message.new(select(index +1 ,'Sunday','Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday')):plain()
	end
end

local function julian_month_name(index)
	if cfg.gregorian_months and #cfg.gregorian_months==12 then
		return cfg.gregorian_months[index]
	else
		return mw.message.new(select(index, 'january', 'february', 'march', 'april', 'may_long', 'june', 'july', 'august', 'september', 'october', 'november', 'december')):plain()
	end
end

local format_func = {
	towdigit = towdigit,
	hijri_month_name = hijri_month_name,
	wday_name = wday_name,
	julian_month_name = julian_month_name
}

local function substitute( msg, args )
	return args and mw.message.newRawMessage( msg, args ):plain() or msg;
end

local function error( msg, args )
	return substitute( cfg.presentation.error, substitute( msg, args ) );
end


local function argument_wrapper(arg)
	local nilargs = {}
	return setmetatable({},
	{
		__index = function ( tbl, k )
			local v = rawget(tbl,k)
			if v then
				return v
			elseif nilargs[k] then
				return nil
			end
			local list = cfg.aliases[k];
			for _,arglist in ipairs(arg) do
				if type( list ) == 'table' then
					for _, alias_key in ipairs( list ) do
						if arglist[alias_key] then
							v = arglist[alias_key]
							break;
						end
					end
				elseif list ~= nil then
					v = arglist[list]
				end

				if v then
					break;
				end
			end
			if v == nil then
				nilargs[k] = true
			else
				rawset( tbl, k, v )
			end
			return v
		end,
	});
end

local function get_value_from_aliaes(aliases_tbl, arg_value)
	if arg_value  and aliases_tbl then
		for k, v_list in pairs(aliases_tbl) do
			if type(v_list) ~= "table" then
				if arg_value == v_list then
					return k
				end
			else
				for _, v_value in ipairs(v_list) do
					if arg_value == v_value then
						return k
					end
				end
			end
		end	
	end
end
--[[ -------------------- frame functions ---------------------------------------]]
local function test(frame)
	return mw.language.getContentLanguage():formatDate("Y n j", '@-86400' ,true)
end

function get_gregorian_from_hijri(frame)
	return mw.text.listToText({ hijri2gregorian(tonumber(frame.args[1]),tonumber(frame.args[2]),tonumber(frame.args[3])) },"-","-")
end

function get_hijri_from_gregorian(frame)
	d= Date(str_hijri_mode)
	d:from_gregorian(tonumber(frame.args[1]),tonumber(frame.args[2]),tonumber(frame.args[3]))
	return d
end

local function lua_format_date(A)
	local theformat = A.format or 'xmj xmF xmY'
	local cDate
	if A.year and A.day and A.month then
		local year, month, day = tonumber(A.year), tonumber(A.month), tonumber(A.day)
		local source_cal = get_value_from_aliaes(cfg.cal_aliases, A.source_cal)
		if not source_cal then
			if day>30 or year > 1500 then
				source_cal = 'gregorian'
			else
				source_cal='hijri'
			end
		end
		local wday = get_value_from_aliaes(cfg.wday_aliases, A.wday)
		if source_cal == 'hijri' then
			cDate = Date(str_hijri_mode)
			if wday then
				cDate:from_hijri(year,month,day,wday,cfg.hijri_mode)
			else
				cDate:set_date(year,month,day,true)
			end
		else
			cDate = Date(source_cal)
			if string.sub(source_cal,1,5) == 'hijri' and wday then
				cDate:from_hijri(year,month,day,wday)
			else
				cDate:set_date(year,month,day)
			end
		end
	elseif A.date then
		local tmpdate = mw.language.getContentLanguage():formatDate('Y/n/j', A.date)
		if tmpdate then
			local gre = mw.text.split(tmpdate,'/')
			cDate = Date('gregorian',tonumber(gre[1]), tonumber(gre[2]), tonumber(gre[3]))
		else
			cDate = Date('gregorian')
		end
	else
		cDate = Date('gregorian')
	end

	if string.find(theformat, 'x[muwg][jFntYyzdm]') or string.find(theformat, '~[هميغ][يشرسلةع]0?') then
		local lc_hijri_mode = get_value_from_aliaes(cfg.cal_aliases, A.hijri_cal_type) or str_hijri_mode
		-- date replaces
		local symbols = cfg.symbol_replace.symbols
		local dr = cfg.symbol_replace.calendars
		local pat, cal_type
		for drk,drv in pairs(dr) do
			cal_type = (drk == 'hijri') and lc_hijri_mode or drv.type
			for sym_pre_i, sym_pre in ipairs(drv.sym_pre) do
				if drv.symbols_pattern then
					pat = drv.symbols_pattern[sym_pre_i]
				else
					pat = sym_pre .. cfg.symbol_replace.default_symbol_pattern[sym_pre_i]
				end
				if string.find(theformat,pat) then
					cDate:set_type(cal_type)
					local tempformat,sy = theformat,''
					local ss,se = string.find(tempformat,pat)
					theformat = ''
					while ss do
						sy = string.sub(tempformat,ss,se)

						if ss > 1 then
							theformat = theformat .. string.sub(tempformat,1,ss-1)
						end
						
						if se < #tempformat then
							tempformat = string.sub(tempformat,se+1)
						else
							tempformat = ''
						end
					
						for sym, symv in pairs(symbols[sym_pre_i]) do
							if sy == sym_pre .. sym then
								if symv.func then
									if format_func[symv.func] then
										theformat = theformat .. format_func[symv.func](cDate[symv.rep])
									elseif format_func[drv.func[symv.func]] then
										theformat = theformat .. format_func[drv.func[symv.func]](cDate[symv.rep])
									else
										error('Can`t find fromating function')
									end
								else
									theformat = theformat .. cDate[symv.rep]
								end
							end
						end
						ss,se = string.find(tempformat,pat)
					end
					theformat = theformat .. tempformat
				end
			end
		end
	end
	if string.find(theformat,"[a-zA-Z]") and (not A.pass_mw_time or A.pass_mw_time == '1' or A.pass_mw_time == 'نعم')  then
		cDate:set_type('gregorian')
		return  mw.language.getContentLanguage():formatDate(theformat, cDate.timestamp and ("@" .. cDate.timestamp) or cDate ,true)
	else
		return theformat
	end
end

local function format_date(frame)
	local A = argument_wrapper({frame:getParent().args, frame.args})
	return lua_format_date(A)
end

return { test = test,
	get_gregorian_from_hijri = get_gregorian_from_hijri,
	get_hijri_from_gregorian =get_hijri_from_gregorian,
	format_date = format_date,
	lua_format_date=lua_format_date,
	julian_month_name = julian_month_name,
	hijri_month_name = hijri_month_name
}