local M = {}

function M.calcSpread(api, ammoCnt, basicInaccuracy)
    local cache = api:getCachedScriptData()
    local angle = 0.5 - ammoCnt / 20
    if (api:getAimingProgress() > 0) then
        return {0, angle * 10}
    elseif(cache.attack_count == 2) then
        return {0, angle * 5}
    else
        return {angle * 15, 0}
    end
end

-- 尝试开火射击时调用
function M.shoot(api)
    local cache = api:getCachedScriptData()
    if (cache == nil) then
        cache = {
            attack_count = 0
        }
    end

    -- 先从data文件中获取开火延迟数据，由于以毫秒为单位，因此将秒乘以1000转为毫秒
    local shoot_delay = api:getScriptParams().shoot_delay * 1000

    if (api:getAimingProgress() > 0) then
        api:adjustShootInterval(api:getShootInterval() + 200)
        shoot_delay = api:getScriptParams().heavy_delay * 1000
    end

    -- 获取上次射击的 timestamp（系统时间，单位毫秒）
    local last_shoot_timestamp = api:getLastShootTimestamp()
    -- 获取当前系统时间
    local current_timestamp = api:getCurrentTimestamp()
    -- 获取枪械的射击间隔，单位毫秒。用于判断是否在连射，也用于调整射击间隔
    local shoot_interval = api:getShootInterval()
    -- 判断是否在连射，给 2 tick 宽容时间
    if (current_timestamp - last_shoot_timestamp < shoot_interval + 1000) then
        cache.attack_count = (cache.attack_count + 1) % 3
    else
        cache.attack_count = 0
    end

    -- 将执行射击的部分委托为一次性的延时任务，从而达到延迟开火的目的
    api:safeAsyncTask(function ()
        api:shootOnce(false)
        return false
    end,shoot_delay,0,1)

    api:cacheScriptData(cache)
end

function M.start_reload(api)
    -- Initialize cache that will be used in reload ticking
    local cache = {
        is_tactical = api:getReloadStateType() == TACTICAL_RELOAD_FEEDING,
    }
    api:cacheScriptData(cache)
    -- Return true to start ticking
    return true
end

function M.tick_reload(api)
    local cache = api:getCachedScriptData()

    local power_open = api:getScriptParams().power_open * 1000
    local power_feed = api:getScriptParams().power_feed * 1000
    local power_close = api:getScriptParams().power_close * 1000
    local reload_time = api:getReloadTime()

    if (api:isOverheatLocked()) then
        return NOT_RELOADING, -1
    end
    if (not cache.is_tactical) then
        if (reload_time < power_feed) then
            return TACTICAL_RELOAD_FEEDING, power_feed - reload_time
        elseif (reload_time >= power_feed and reload_time < power_open) then
            api:putAmmoInMagazine(1)
            return TACTICAL_RELOAD_FINISHING, power_open - reload_time
        else
            return NOT_RELOADING, -1
        end
    else
        if (reload_time < power_feed) then
            return EMPTY_RELOAD_FEEDING, power_feed - reload_time
        elseif (reload_time >= power_feed and reload_time < power_close) then
            api:reduceAmmoOnce()
            api:removeAmmoFromMagazine(1)
            return EMPTY_RELOAD_FINISHING, power_close - reload_time
        else
            return NOT_RELOADING, -1
        end
    end
end

local function tick_normal(api, heatTimestamp)
    local delay = api:getCoolingDelay()
    local now = api:getCurrentTimestamp()

    if (now - heatTimestamp >= delay and not api:hasAmmoInBarrel()) then
        local heat = api:getHeatAmount() - api:calcHeatReduction(heatTimestamp)
        api:setHeatAmount(heat)
    else
        local heat = api:getHeatAmount() + api:calcHeatReduction(heatTimestamp)
        api:setHeatAmount(heat)
        if heat >= api:getHeatMax() then
            api:reduceAmmoOnce()
            api:removeAmmoFromMagazine(1)
            api:setOverheatLocked(true)
        end
    end
end

local function tick_locked(api, heatTimestamp)
    local overheatTime = api:getOverheatTime()
    local now = api:getCurrentTimestamp()

    if now - heatTimestamp >= overheatTime then
        local heat = api:getHeatAmount() - api:calcHeatReduction(heatTimestamp)
        api:setHeatAmount(heat)
        if heat <= 0 then
            api:setOverheatLocked(false)
        end
    end
end

function M.tick_heat(api, heatTimestamp)
    if api:hasHeatData() then
        if api:isOverheatLocked() then
            tick_locked(api, heatTimestamp)
        else
            tick_normal(api, heatTimestamp)
        end
    end
end

-- 警告，此方法是shootOnce的一部分，不要在此处尝试射击，不然会死循环
function M.handle_shoot_heat(api)
    if api:hasHeatData() then
        local heatMax = api:getHeatMax()
        local heat = math.min(api:getHeatAmount() + api:getHeatPerShot(), heatMax)
        api:setHeatAmount(heat)
        if heat >= heatMax then
            api:reduceAmmoOnce()
            api:removeAmmoFromMagazine(1)
            api:setOverheatLocked(true)
        end
    end
end

return M