local _AddonName, _EchoRaidTools = ...;


local module = _EchoRaidTools:GetModule("todo-list")

local currentState = {}
local timers = {}
local timerTicker
module.display = module.display or {}



local function processBarUpdate(identifier, min, max, current)
    local mod = currentState[identifier]
    min = min or mod.min or 0
    max = max or mod.total or 1
    current = current or mod.value or 0
    local barValue
    if current <= min then
        barValue = 0
    elseif current >= max then
        barValue = 1
    elseif max <= min then
        barValue = 0
    else
        barValue = (current - min) / (max - min)
    end


    --print("bar value", barValue, "min", min, "max", max, "current", current)
    module.display.UpdateValue(identifier, barValue)
end

local function updateTimers()
    for identifier, func in pairs(timers) do
        func()
    end
end
function module.display.checkTimerState()
    local timerExists = next(timers) and true or false
    local displayIsVisible = module:GetShownState()
    local tickerExists = timerTicker and true or false

    if displayIsVisible and timerExists and not tickerExists then
        updateTimers()
        timerTicker = C_Timer.NewTicker(1, updateTimers)
    elseif tickerExists and not (displayIsVisible and timerExists) then
        timerTicker:Cancel()
        timerTicker = nil
    end
end

local function removeTimer(identifier)
    if not timers[identifier] then return end
    timers[identifier] = nil
    module.display.checkTimerState()

    local mod = currentState[identifier]
    if not mod then return end

    processBarUpdate(identifier)
    module.display.UpdateProgressText(identifier, mod.progressText, mod)
end

local function addTimer(identifier, func)
    func()
    timers[identifier] = func
    module.display.checkTimerState()
end


local function updateTimer(identifier, _, state)
    if state.value >= state.total or not state.enableTimer then
        removeTimer(identifier)
        return
    end
    local timer = state.timer or {}

    local interval = timer.interval or 604800 --one weekly reset
    local offset = timer.offset or 9
    local duration = timer.duration or 0

    local serverOffset = module.GetServerOffset()



    --C_DateAndTime.GetSecondsUntilWeeklyReset()
    --C_DateAndTime.GetSecondsUntilDailyReset()
    ---if it happens once an hour with 10 minute duration, how'd that look?
    ---offset 0
    ---duration 10
    ---interval 50
    ---interval + duration /
    local function func()
        if state.value >= state.total then
            removeTimer(identifier)
            return
        end
        local progressText = ""
        local currentTime = GetServerTime() - C_DateAndTime.GetWeeklyResetStartTime() + serverOffset + offset
        local time = (currentTime % (interval))
        local eventUptime = duration - time
        local timeUntilNextEvent = interval - time
        local max, current
        if eventUptime > 0 then
            progressText = "Active:" .. module:SecondsToHumanTime(eventUptime)
            max = duration
            current = eventUptime
        else
            progressText = module:SecondsToHumanTime(timeUntilNextEvent)
            max = interval - duration
            current = timeUntilNextEvent
        end

        module.display.UpdateProgressText(identifier, progressText)
        processBarUpdate(identifier, 0, max, current)
    end
    addTimer(identifier, func)
end


--TODO make some cool deadline system. countdown til reset etc

---if timer exists then start a 1 second ticker, should there be a countdown bar, or just text time? where would the bar even be? hmmge
---need offset, duration, cooldown
---tama just uses the bar and right text as countdown
---GetServerTime() - C_DateAndTime.GetWeeklyResetStartTime() = time since reset
---need to add per region offset somewhere
---module.GetServerOffset()




local function processValueUpdate(identifier, value, state)
    processBarUpdate(identifier, nil, nil, value)
end

local function processTotalUpdate(identifier, total, state)
    processBarUpdate(identifier, nil, total, nil)
end

local function processMinUpdate(identifier, min, state)
    processBarUpdate(identifier, min, nil, nil)
end


local function processIndexUpdate(identifier, index, state)
    if state.isDefaultMod then
        index = index + 1000
    end
    module.display.UpdateIndex(identifier, index, state)
end

local keysToCheck = {
    ["text"] = module.display.UpdateText,
    ["progressText"] = module.display.UpdateProgressText,
    ["value"] = processValueUpdate, -- TODO rename current maybe? idk
    ["total"] = processTotalUpdate, -- TODO rename max
    ["index"] = processIndexUpdate,
    ["colour"] = module.display.UpdateColour,
    ["progressTextColour"] = module.display.UpdateProgressTextColour,
    ["bgColour"] = module.display.UpdateBgColour,
    ["progressTextFontSize"] = module.display.UpdateProgressTextFontSize,
    ["textColour"] = module.display.UpdateTextColour,
    ["textFontSize"] = module.display.UpdateTextFontSize,
    ["timer"] = updateTimer,
    ["enableTimer"] = updateTimer,
    ["height"] = module.display.UpdateHeight,
    ["texture"] = module.display.UpdateTexture,
    ["font"] = module.display.UpdateFont,
    ["icon"] = module.display.UpdateIcon,
    ["min"] = processMinUpdate,
}







local function addMod(state) --add to display
    local identifier = state.identifier
    if currentState[identifier] then return end
    if state.completed and state.hideOnComplete then return end
    module:applyDefaultFieldsToState(state)

    --if state.timer deal with timers here instead? hmmge

    --    EchoRaidToolsDB.TodoList.display.barSettings = { texture = "Solid", font = "Expressway MonoNum", height = 20, alpha = 1, }



    --   print("addmod backend")
    --  if not module:GetShownState() then return end-- this would only get called when eventHandler is running,
    currentState[identifier] = {}
    --might need something else here
    module:CreateBar(identifier)
end

local function removeMod(state)
    local identifier = state.identifier
    if not currentState[identifier] then return end
    module:DestroyBar(identifier)
    --kill display,
    currentState[identifier] = nil
    removeTimer(identifier)
end





---@param state table
function module:ProcessValueUpdate(state)
    if not state then
        return
    end
    if not state.identifier then
        return
    end

    if state.disabled then
        removeMod(state)
        return
    end

    state.completed = state.value and state.total and state.value >= state.total or false

    if not currentState[state.identifier] then
        addMod(state)
    end


    if state.completed then
        if state.unregisterOnCompletion then
            module.eventHandler:UnregisterAllModEvents(state.identifier)
        end
        if state.hideOnComplete then
            removeMod(state)
            return
        end
    end

    --check if values changed, if they did then poke frontend
    local mod = currentState[state.identifier]
    for key, func in pairs(keysToCheck) do
        --we could simplify this function if func provided the paths that were updated, it would move some complexity elsewhere though
        if not module:DeepCompare(state[key], mod[key]) then --don't match, update value
            func(state.identifier, state[key], state)
            mod[key] = module:DeepCopy(state[key])
        end
    end
end

function module:Show()
    if module.display.IsShown then return end
    module.display.ShowDisplay()
end

function module:Hide()
    if not module.display.IsShown then return end
    module.display.HideDisplay()
end

---@return boolean
function module:GetShownState()
    return module.display.IsShown;
end
