local re = re
local sdk = sdk
local d2d = d2d
local imgui = imgui
local log = log
local json = json
local draw = draw
local require = require
local tostring = tostring
local pairs = pairs
local ipairs = ipairs
local math = math
local string = string
local table = table
local type = type

local Core = require("_CatLib")

local MOD_NAME = "Pause Meal Out Of Battle"
local mod = Core.NewMod(MOD_NAME)
-- mod.EnableCJKFont(18) -- if needed
if mod.Config.DoNotPauseInMisson == nil then
    mod.Config.DoNotPauseInMisson = true
end
if mod.Config.DoNotPauseWhenMantle == nil then
    mod.Config.DoNotPauseWhenMantle = true
end

if mod.Config.AlsoPauseStamina == nil then
    mod.Config.AlsoPauseStamina = true
end

local function IsPaused()
    local shouldCount = Core.IsInBattle()

    if mod.Config.DoNotPauseInMisson and Core.IsPlayingQuest() then
        shouldCount = true
    end

    if mod.Config.DoNotPauseWhenMantle and Core.IsWearMantle() then
        shouldCount = true
    end

    return not shouldCount
end

local CurrentMealTimer = nil
-- local CurrentHealthTimer = nil

local Hunter
local HunterStatus
local HunterStamina

Core.OnLoading(function ()
    Hunter = nil
    HunterStatus = nil
    HunterStamina = nil
end)

local function InitHunterFields()
    if not Hunter then
        Hunter = Core.GetPlayerCharacter()
    end
    if not Hunter then return end

    if not HunterStatus then
        HunterStatus = Hunter:get_HunterStatus()
    end
    if not HunterStamina then
        HunterStamina = Hunter:get_HunterStamina()
    end
end

mod.OnUpdateBehavior(function ()
    InitHunterFields()
    if not HunterStatus then return end

    local meal = HunterStatus._MealEffect
    if not meal then return end

    local paused = IsPaused()

    if (not paused) or (not CurrentMealTimer) or math.abs(meal._DurationTimer - CurrentMealTimer) > 1 then
        -- update last counted timer
        CurrentMealTimer = meal._DurationTimer
    end

    if paused and CurrentMealTimer then
        meal:set_field("_DurationTimer", CurrentMealTimer)
    end
end)

local CurrentStaminaTimer = nil
local staminaTable = {}
-- todo vtable hook?
mod.HookFunc("app.cHunterStamina", "update(System.Single)",
function (args)
    if not mod.Config.AlsoPauseStamina then return end

    InitHunterFields()
    if not HunterStamina then return end

    local this = sdk.to_managed_object(args[2])
    if this ~= HunterStamina then return end

    local timer = this:get_AutoMaxReduceTimer()

    if mod.Config.Debug then
        staminaTable[this] = {
            Stamina = this:get_Stamina(),
            MaxStamina = this:get_MaxStamina(),
            StaminaTough = this:get_StaminaTough(),
            MaxStaminaTough = this:get_MaxStaminaTough(),
            StaminaLimit = this:get_StaminaLimit(),
            AutoMaxReduceTimer = timer,
        }
    end

    local paused = IsPaused()

    if (not paused) or (not CurrentStaminaTimer) or math.abs(timer - CurrentStaminaTimer) > 1 then
        CurrentStaminaTimer = timer
    end

    if paused and CurrentStaminaTimer then
        HunterStamina:setAutoMaxReduceTimer(CurrentStaminaTimer)
    end
end)

mod.OnDebugFrame(function ()
    local hunter = Core.GetPlayerCharacter()
    if not hunter then return end
    local status = hunter:get_HunterStatus()
    if not status then return end

    local meal = status._MealEffect
    imgui.text("Duration: " .. Core.FloatFixed1(meal._DurationTimer) .. "/" .. Core.FloatFixed1(meal._TimerMax))
    imgui.text("In Battle: " .. tostring(Core.IsInBattle()))

    local missionMgr = Core.GetMissionManager()
    imgui.text("get_IsActiveQuest: " .. tostring(missionMgr:get_IsActiveQuest()))
    imgui.text("get_IsPlayingQuest: " .. tostring(missionMgr:get_IsPlayingQuest()))
    -- imgui.text("Enemy Count: " .. tostring(missionMgr:getAcceptQuestTargetBrowsers():get_Count() > 0))

    local armorCtrl = hunter:get_ArmorCtrl()
    imgui.text("_IsMantleOff: " .. tostring(armorCtrl._IsMantleOff))
    imgui.text("_IsPutOnMantle: " .. tostring(armorCtrl._IsPutOnMantle))
    imgui.text("Meal Timer: " .. tostring(CurrentMealTimer))
    imgui.text("Stamina Timer: " .. tostring(CurrentStaminaTimer))
    local stamina = hunter:get_HunterStamina()
    if stamina then
        if staminaTable[stamina] then
            local data = staminaTable[stamina]
            imgui.text("SP: " .. Core.FloatFixed1(data.Stamina) .. "/" .. Core.FloatFixed1(data.MaxStamina))
            imgui.text("SP Tough: " .. Core.FloatFixed1(data.StaminaTough) .. "/" .. Core.FloatFixed1(data.MaxStaminaTough))
            imgui.text("SP Limit: " .. Core.FloatFixed1(data.StaminaLimit))
            imgui.text("SP Reduce Timer: " .. Core.FloatFixed1(data.AutoMaxReduceTimer))
            imgui.text("SP TableSize: " .. tostring(Core.GetTableSize(staminaTable)))
        end
    end

end)

mod.Menu(function ()
	local configChanged = false
    local changed = false

    changed, mod.Config.DoNotPauseInMisson = imgui.checkbox("Don't Pause In Misson", mod.Config.DoNotPauseInMisson)
    configChanged = configChanged or changed

    changed, mod.Config.DoNotPauseWhenMantle = imgui.checkbox("Don't Pause When Mantle", mod.Config.DoNotPauseWhenMantle)
    configChanged = configChanged or changed

    changed, mod.Config.AlsoPauseStamina = imgui.checkbox("Also Pause Stamina", mod.Config.AlsoPauseStamina)
    configChanged = configChanged or changed

    if mod.Config.Debug then
        if imgui.button("Set meal timer to 10") then
            local func = function ()
                local hunter = Core.GetPlayerCharacter()
                if not hunter then return end
                local status = hunter:get_HunterStatus()
                if not status then return end

                local meal = status._MealEffect
                CurrentMealTimer = 10
                meal:set_field("_DurationTimer", 10)
            end
            func()
        end
    end

    return configChanged
end)
