local M = {}
M.type = "auxiliary"
M.relevantDevice = nil

local htmlTexture = require("htmlTexture")

local gaugesScreenName = nil
local htmlPath = nil
local gaugeData = {electrics = {}}

local previousFuel = 0
local fuelSmoother = newTemporalSmoothing(50, 50)
local fuelDisplaySmoother = newTemporalSmoothing(5, 3)
local avgFuelSum = 0
local avgFuelCounter = 0
local updateTimer = 0
local updateFPS = 30
local invFPS = 1 / updateFPS

local previousIgnitionState = nil

local previousVoltsVal = 14.9
local voltageRampRate = 0.1

local function calculateTiming(boost, tps, rpm)
    local idleTiming = 12
    local maxTiming = 40
    local boostRetardPerPSI = 0.3
    local tpsEffect = tps * 15
    local rpmEffect = (rpm / 10000) * 13

    local timing = idleTiming + tpsEffect + rpmEffect

    timing = timing - (boost * boostRetardPerPSI)

    local randomVariation = math.random(-1, 1)
    timing = timing + randomVariation

    timing = math.max(10, math.min(maxTiming, timing))

    return timing
end

local function calculateBatteryVoltage(rpm, maxRPM, ignitionState, dt)
    local targetVoltsVal = 14.9

    if ignitionState == 3 then
        targetVoltsVal = 11.3
    else
        if rpm < 200 then
            targetVoltsVal = 13.2
        else
            if rpm > 700 then
                targetVoltsVal = 14.7
            else
                targetVoltsVal = 14.7
            end

            local rpmProportion = math.min(rpm / maxRPM, 1)
            targetVoltsVal = targetVoltsVal - (0.2 * rpmProportion)

            targetVoltsVal = targetVoltsVal + (math.random() * 0.4 - 0.2)
        end
    end

    if previousVoltsVal < targetVoltsVal then
        previousVoltsVal = math.min(previousVoltsVal + voltageRampRate, targetVoltsVal)
    elseif previousVoltsVal > targetVoltsVal then
        previousVoltsVal = math.max(previousVoltsVal - voltageRampRate, targetVoltsVal)
    end

    previousVoltsVal = math.max(11.0, math.min(previousVoltsVal, 15.0))

    local voltsVal = tonumber(string.format("%.1f", previousVoltsVal))

    print(string.format("RPM: %d, MaxRPM: %d, Ignition State: %d, VoltsVal: %.1f V", rpm, maxRPM, ignitionState, voltsVal))

    return voltsVal
end

local function updateGFX(dt)
    updateTimer = updateTimer + dt
    if updateTimer > invFPS then
        local data = {}
        local wheelspeed = electrics.values.wheelspeed or 0
        local rpm = electrics.values.rpm or 0
        local boost = electrics.values.turboBoost or electrics.values.boost or 0
        local tps = electrics.values.throttle or 0
        local maxRPM = electrics.values.maxrpm or 8000

        data.gear = electrics.values.gear
        data.fuel = electrics.values.fuel
        data.oiltemp = math.floor(electrics.values.oiltemp)
        data.ripems = math.floor(rpm)
        data.boost = boost
        data.watertemp = electrics.values.watertemp or 0
        data.gps = electrics.values.airspeed or 0
        data.speed = wheelspeed
        data.ign = electrics.values.ignitionLevel
        data.maxRpm = maxRPM

        data.twoStep = electrics.values.twoStep or false

        if rpm < 100 then
            data.blackout = true
        else
            data.blackout = false
        end

        data.timing = calculateTiming(boost, tps, rpm)

        data.voltsVal = calculateBatteryVoltage(rpm, maxRPM, data.ign, dt)

        if previousIgnitionState ~= data.ign then
            print(string.format("Ignition State Changed: %d", data.ign))
            previousIgnitionState = data.ign
        end

        htmlTexture.call(gaugesScreenName, "updateData", data)
        updateTimer = 0
    end
end

local function init(jbeamData)
    previousFuel = 0
    avgFuelSum = 0
    avgFuelCounter = 0
    fuelSmoother:reset()
    fuelDisplaySmoother:reset()
    gaugesScreenName = jbeamData.materialName
    htmlPath = jbeamData.htmlPath
    local unitType = jbeamData.unitType or "metric"
    local width = jbeamData.textureWidth or 512
    local height = jbeamData.textureHeight or 256

    htmlTexture.create(gaugesScreenName, htmlPath, width, height, updateFPS, "automatic")
end

M.init = init
M.updateGFX = updateGFX

return M
