Documentation icon މޮޑިއުލް ޑޮކިއުމަންޓޭޝަން[create]
local p = {}

-- Table to convert entered text values to numeric values.
local timeText = {
    ['ސިކުންތު'] = 1,
    ['މިނިޓު'] = 60,
    ['ގަޑި'] = 3600,
    ['ދުވަސް'] = 86400,
    ['ހަފްތާ'] = 604800,
    ['މަސް'] = 2629800,  -- 365.25 * 24 * 60 * 60 / 12
    ['އަހަރު'] = 31557600
}

-- Table containing tables of possible units to use in output.
local timeUnits = {
    [1] = { 'ސިކުންތު', 'seconds', "second's", "seconds'" },
    [60] = { 'މިނިޓު', 'minutes', "minutes'", "minutes'" },
    [3600] = { 'ގަޑި', 'hours', "hour's", "hours'" },
    [86400] = { 'ދުވަސް', 'days', "day's", "days'" },
    [604800] = { 'ހަފްތާ', 'weeks', "week's", "weeks'", unit = 'w' },
    [2629800] = { 'މަސް', 'months', "month's", "months'", unit = 'm'  },
    [31557600] = { 'އަހަރު', 'އަހަރު', "year's", "years'", unit = 'y'  }
}

-- Determine suffix based on the time difference
local suffixes = {
    past = 'ކުރިން',  -- ago
    future = 'ކުރިން ބައި',  -- time (for future)
}

function p._main(args)
    -- Initialize variables
    local lang = mw.language.getContentLanguage()
    local auto_magnitude_num
    local min_magnitude_num
    local magnitude = args.magnitude
    local min_magnitude = args.min_magnitude
    local purge = args.purge

    -- Add a purge link if something (usually "yes") is entered into the purge parameter
    if purge then
        purge = ' <span class="plainlinks">([' .. mw.title.getCurrentTitle():fullUrl('action=purge') .. ' purge])</span>'
    else
        purge = ''
    end

    -- Check that the entered timestamp is valid. If it isn't, then give an error message.
    local success, inputTime = pcall(lang.formatDate, lang, 'xnU', args[1])
    if not success then
        return '<strong class="error">Error: first parameter cannot be parsed as a date or time.</strong>'
    end

    -- Store the difference between the current time and the inputted time, as well as its absolute value.
    local timeDiff = lang:formatDate('xnU') - inputTime
    local absTimeDiff = math.abs(timeDiff)

    if magnitude then
        auto_magnitude_num = 0
        min_magnitude_num = timeText[magnitude]
    else
        -- Calculate the appropriate unit of time if it was not specified as an argument.
        local autoMagnitudeData = {
            { factor = 2, amn = 31557600 },
            { factor = 2, amn = 2629800 },
            { factor = 2, amn = 86400 },
            { factor = 2, amn = 3600 },
            { factor = 2, amn = 60 }
        }
        for _, t in ipairs(autoMagnitudeData) do
            if absTimeDiff / t.amn >= t.factor then
                auto_magnitude_num = t.amn
                break
            end
        end
        auto_magnitude_num = auto_magnitude_num or 1
        if min_magnitude then
            min_magnitude_num = timeText[min_magnitude]
        else
            min_magnitude_num = -1
        end
    end

    if not min_magnitude_num then
        -- Default to seconds if an invalid magnitude is entered.
        min_magnitude_num = 1
    end

    local result_num
    local magnitude_num = math.max(min_magnitude_num, auto_magnitude_num)
    local unit = timeUnits[magnitude_num].unit
    if unit and absTimeDiff >= 864000 then
        local Date = require('Module:Date')._Date
        local input = lang:formatDate('Y-m-d H:i:s', args[1])  -- Date needs a clean date
        input = Date(input)
        if input then
            local id
            if input.hour == 0 and input.minute == 0 then
                id = 'currentdate'
            else
                id = 'currentdatetime'
            end
            result_num = (Date(id) - input):age(unit)
        end
    end
    result_num = result_num or math.floor(absTimeDiff / magnitude_num)

    local punctuation_key, suffix
    if timeDiff >= 0 then -- Past
        if result_num == 1 then
            punctuation_key = 1
        else
            punctuation_key = 2
        end
        suffix = args.ago == '' and '' or ' ' .. suffixes.past
    else -- Future
        if args.ago == '' then
            suffix = ''
            if result_num == 1 then
                punctuation_key = 1
            else
                punctuation_key = 2
            end
        else
            suffix = ' ' .. suffixes.future
            if result_num == 1 then
                punctuation_key = 3
            else
                punctuation_key = 4
            end
        end
    end
    local result_unit = timeUnits[magnitude_num][punctuation_key]

    -- Convert numerals to words if appropriate.
    local spell_out = args.spellout
    local spell_out_max = tonumber(args.spelloutmax)
    local result_num_text
    if spell_out and (
        (spell_out == 'auto' and 1 <= result_num and result_num <= 9 and result_num <= (spell_out_max or 9)) or
        (yesno(spell_out) and 1 <= result_num and result_num <= 100 and result_num <= (spell_out_max or 100))
    )
    then
        result_num_text = numberSpell(result_num)
    else
        result_num_text = tostring(result_num)
    end

    -- numeric or string
    local numeric_out = args.numeric
    local result = ""
    if numeric_out then
        result = tostring(result_num)
    else
        result = result_num_text .. ' ' .. result_unit .. suffix -- Spaces for suffix have been added in earlier.
    end

    return result .. purge
end

function p.main(frame)
    local args = require('Module:Arguments').getArgs(frame, {
        valueFunc = function(k, v)
            if v then
                v = v:match('^%s*(.-)%s*$') -- Trim whitespace.
                if k == 'ago' or v ~= '' then
                    return v
                end
            end
            return nil
        end,
        wrappers = 'Template:Time ago'
    })
    return p._main(args)
end

return p