require "TimedActions/ISBaseTimedAction"

--------------------------------------------------
-- Core Injector System
--------------------------------------------------
SCPInjectors = SCPInjectors or {}

--------------------------------------------------
-- Shared Sayings
--------------------------------------------------
SCPInjectors.Sayings = {
    "UI_Saying_1", "UI_Saying_2", "UI_Saying_3", "UI_Saying_4", "UI_Saying_5",
    "UI_Saying_6", "UI_Saying_7", "UI_Saying_8", "UI_Saying_9", "UI_Saying_10",
    "UI_Saying_11", "UI_Saying_12", "UI_Saying_13", "UI_Saying_14", "UI_Saying_15",
    "UI_Saying_16", "UI_Saying_17", "UI_Saying_18", "UI_Saying_19", "UI_Saying_20",
}

--------------------------------------------------
-- Adrenal Surge Crash Logic Helpers
--------------------------------------------------
local SCP_ADRENAL_CRASH_DELAY_MINUTES = 60

local function getMinutesStampSafe()
    local gt = getGameTime()

    if not gt then
        return 0
    end

    return math.floor(gt:getWorldAgeHours() * 60)
end

--------------------------------------------------
-- Injector Definitions
--------------------------------------------------
SCPInjectors.Definitions = {

    --------------------------------------------------
    -- Hemovita 
    --------------------------------------------------
    ["Base.SCP_Injector_Hemovita"] = {
        emptyItem = "Base.EmptyInjector",
        sound = "SCP_Injector_Sound",
        actionTime = 40,

        onInject = function(character, item)
            local dizzyAmount = 40
            local hungerAmount = 0.4
            local thirstAmount = 0.4

            local bodyDamage = character:getBodyDamage()
            local maxHealth = (bodyDamage.getMaxHealth and bodyDamage:getMaxHealth()) or 100
            local currentHealth = bodyDamage:getHealth()
            local missingHealth = math.max(0, maxHealth - currentHealth)

            local healAmount = missingHealth * 0.58
            
            -- Needs a multiplier because addGeneralHealth is not linear with the health bar
            local healValue = healAmount * 4

            if healValue > 0 then
                bodyDamage:AddGeneralHealth(healValue)
            end

            character:getStats():add(CharacterStat.INTOXICATION, dizzyAmount)
            character:getStats():add(CharacterStat.HUNGER, hungerAmount)
            character:getStats():add(CharacterStat.THIRST, thirstAmount)
        end,
    },

    --------------------------------------------------
    -- Adrenal Surge
    --------------------------------------------------
    ["Base.SCP_Injector_AdrenalSurge"] = {
        emptyItem = "Base.EmptyInjector",
        sound = "SCP_Injector_Sound",
        actionTime = 40,

        onInject = function(character, item)
            local stats = character:getStats()

            stats:add(CharacterStat.ENDURANCE, 0.4)

            local md = character:getModData()
            md.SCP_AdrenalSurgeCrashMinuteStamp = getMinutesStampSafe() + SCP_ADRENAL_CRASH_DELAY_MINUTES
        end,
    },
}

--------------------------------------------------
-- Adrenal Surge Crash Logic
--------------------------------------------------
local function applyAdrenalSurgeCrash(player)
    if not player or player:isDead() then return end

    local stats = player:getStats()

    stats:add(CharacterStat.ENDURANCE, -0.9)
    stats:add(CharacterStat.THIRST, 0.95)

    player:Say(getText("UI_SCP_AdrenalCrash"))
end

local function checkAdrenalSurgeCrash()
    local now = getMinutesStampSafe()
    if now <= 0 then return end

    for i = 0, getNumActivePlayers() - 1 do
        local player = getSpecificPlayer(i)

        if player and not player:isDead() then
            local md = player:getModData()
            local crashStamp = md.SCP_AdrenalSurgeCrashMinuteStamp

            if crashStamp and now >= crashStamp then
                md.SCP_AdrenalSurgeCrashMinuteStamp = nil
                applyAdrenalSurgeCrash(player)
            end
        end
    end
end

Events.EveryTenMinutes.Add(checkAdrenalSurgeCrash)

--------------------------------------------------
-- Consume Injector
--------------------------------------------------
local function consumeInjectorSyringe(action, data)
    action.item:getContainer():setDrawDirty(true)
    action.character:getInventory():Remove(action.item)
    action.character:getInventory():AddItem(data.emptyItem or "Base.EmptyInjector")
end

--------------------------------------------------
-- Say Random Line
--------------------------------------------------
local function sayRandomInjectorLine(character)
    local idx = ZombRand(#SCPInjectors.Sayings) + 1
    character:Say(getText(SCPInjectors.Sayings[idx]))
end

--------------------------------------------------
-- Custom Inject Action
--------------------------------------------------
ISInjectAction = ISBaseTimedAction:derive("ISInjectAction")

function ISInjectAction:isValid()
    return self.item ~= nil and self.character ~= nil
end

function ISInjectAction:start()
    if self.data.sound then
        self.character:getEmitter():playSound(self.data.sound)
    end

    self:setOverrideHandModels(self.item, nil)
    self:setActionAnim(CharacterActionAnims.InsertBullets)
end

function ISInjectAction:update()
end

function ISInjectAction:perform()
    if self.data.onInject then
        self.data.onInject(self.character, self.item)
    end

    sayRandomInjectorLine(self.character)
    consumeInjectorSyringe(self, self.data)

    ISBaseTimedAction.perform(self)
end

function ISInjectAction:new(character, item, data)
    local o = ISBaseTimedAction.new(self, character)
    o.character = character
    o.item = item
    o.data = data
    o.maxTime = data.actionTime or 40
    return o
end

--------------------------------------------------
-- Context Menu
--------------------------------------------------
local function onInjectorContextMenu(playerIndex, context, items)
    local player = getSpecificPlayer(playerIndex)
    if not player then return end

    local actualItems = ISInventoryPane.getActualItems(items)

    local injector = nil
    local injectorData = nil
    local onlyInjectors = true

    for _, item in ipairs(actualItems) do
        local data = SCPInjectors.Definitions[item:getFullType()]

        if data then
            if not injector then
                injector = item
                injectorData = data
            end
        else
            onlyInjectors = false
        end
    end

    if not injector or not injectorData then return end

    --------------------------------------------------
    -- Remove "Take Pills" if only injectors selected
    --------------------------------------------------
    if onlyInjectors then
        for i = #context.options, 1, -1 do
            local option = context.options[i]
            if option and option.name == getText("ContextMenu_Take_pills") then
                table.remove(context.options, i)
                context.numOptions = context.numOptions - 1
            end
        end
    end

    --------------------------------------------------
    -- Add Inject Option
    --------------------------------------------------
    local injectOption = context:addOption(getText("ContextMenu_Inject"), injector, function(itm, playerObj, data)
        local inv = playerObj:getInventory()
        local primary = playerObj:getPrimaryHandItem()

        if primary ~= itm then
            local container = itm:getContainer()

            if container and container ~= inv then
                ISTimedActionQueue.add(ISInventoryTransferAction:new(playerObj, itm, container, inv, 0))
            end

            ISTimedActionQueue.add(ISEquipWeaponAction:new(playerObj, itm, 50, true, false))
        end

        ISTimedActionQueue.add(ISInjectAction:new(playerObj, itm, data))
    end, player, injectorData)

    --------------------------------------------------
    -- Add Icon (like vanilla pills)
    --------------------------------------------------
    if injectOption and injector and injector.getTex then
        injectOption.iconTexture = injector:getTex()
    end
end

Events.OnFillInventoryObjectContextMenu.Add(onInjectorContextMenu)