local gui = require("gui")
local color = require("gui.core.color")
local multi, thread = require("multi"):init()

local function startTimer(opt)
    local default = {
        duration = 30,
        autoText = true,
        autoColor = true,
        autoCleanup = false,
        startColor = color.green,
        textColor = color.black,
        warnColor = color.yellow,
        timeColor = color.red,
        finegrained = false,
        visibility = 1
    }

    if type(opt) == "number" then
        local d = opt
        opt = default
        opt.duration = d
    elseif type(opt) ~= "table" then
        opt = default
    else
        for i, v in pairs(opt) do
            default[i] = v
        end
        opt = default
    end

    local timeRemaining = opt.duration or 30

    local tpie = gui:newFrame():makeArc("pie", -200, 0, 100, 1, 0, 0, 1.5*math.pi, 3.5*math.pi, 360)
    local tlabel = tpie:newTextLabel("")
    tlabel.textColor = opt.textColor
    tlabel.align = gui.ALIGN_CENTER
    tlabel:fullFrame()
    tlabel.visibility = 0
    tpie.color = opt.startColor
    tpie.visibility = opt.visibility

    local tm
    local stopped = false
    local onTimeConn = multi:newConnection()
    local onStopConn = multi:newConnection()

    local function cleanup()
        if stopped then return end
        stopped = true
        if onTimeConn and not onTimeConn.destroyed then
            onTimeConn:Destroy()
        end
        if not tpie.destroyed then
            tpie:destroy()
        end
    end

    local timerThread = thread:newThread("Pie Timer", function()
        local startTime = love.timer.getTime()
        local lastSecond = timeRemaining

        while not stopped do
            thread.sleep(1/60)

            local now = love.timer.getTime()
            local elapsed = now - startTime
            local t = math.min(elapsed, timeRemaining)
            local num = timeRemaining - math.floor(t)
            local p = 3.5 - (t / timeRemaining) * 2

            if opt.autoColor then
                tpie.color = opt.startColor
                if num <= timeRemaining / 3 then
                    tpie.color = opt.timeColor
                elseif num <= timeRemaining / 2 then
                    tpie.color = opt.warnColor
                end
            end

            tpie:makeArc("pie", -200, 0, 100, 1, 0, 0, 1.5*math.pi, p*math.pi, 360)

            if opt.autoText then
                tlabel.text = num
                tlabel:fitFont(nil, nil, {scale=1/2})
                tlabel:centerFont()
            end

            if opt.finegrained then
                onTimeConn:Fire(tm, num, t)
            elseif num < lastSecond then
                -- crossed a second boundary
                lastSecond = num
                onTimeConn:Fire(tm, num, t)
            end

            if elapsed >= timeRemaining then
                break
            end
        end

        -- Timer finished
        if stopped then return end

        if opt.autoText then
            tlabel.text = "Time"
            tlabel:fitFont(nil, nil, {scale=1/2})
            tlabel:centerFont()
        end
        tpie:makeArc("pie", -200, 0, 100, 1, 0, 0, 1.5*math.pi, 3.5*math.pi, 360)

        local onStop = onStopConn
        cleanup()
        onStop:Fire(tm)
    end)

    tm = {
        Duration = timeRemaining,
        OnTime = onTimeConn,
        OnStop = onStopConn,
        SetText = function(str) tlabel.text = str end,
        SetColor = function(c) tpie.color = c end,
        Cleanup = function()
            timerThread:Kill()
            cleanup()
        end,
    }

    return tm
end

return {
    startTimer = startTimer
}