local M = {}
M.dependencies = {"ui_imgui"}
local im = ui_imgui
local wndName = '2k_graphics'
local isRain, isSnow
local cubemapname = "Lo_Trees_Cubemap"
local tod, sunsky, clouds, theLevelInfo
local fogDenOriginal

local lightVal, shadowVal
local brightSlider = im.FloatPtr(5)
local streetlightSlider = im.FloatPtr(3)
local streetlightSliderHovered
local ran = false

local function nop() end
local gui_module = require("ge/extensions/editor/api/gui")
local gui = { setupEditorGuiTheme = nop }

-- user prefs fallbacks
userRaysEnabled = 1
userShadowQuality = 0
local userShadowVisibility = 1
streetlightSlider = im.FloatPtr(2)

local showUI = nil
local fadeScreenRunning = false
local skipImgui = false

local function setThemeDark()
    if im.PushStyleColor2 then
        im.PushStyleColor2(im.Col_Text, im.ImVec4(1.0, 1.0, 1.0, 1.0))
        im.PushStyleColor2(im.Col_TitleBg, im.ImVec4(0.0, 0.0, 0.0, 0.4))
        im.PushStyleColor2(im.Col_Border, im.ImVec4(0.0, 0.0, 0.0, 0.2))
        im.PushStyleColor2(im.Col_FrameBg, im.ImVec4(0.0, 0.0, 0.0, 0.5))
        im.PushStyleColor2(im.Col_Button, im.ImVec4(0.0, 0.0, 0.0, 0.5))
        im.PushStyleColor2(im.Col_WindowBg, im.ImVec4(0.0, 0.0, 0.0, 0.4))
        im.PushStyleColor2(im.Col_TitleBgActive, im.ImVec4(0.0, 0.0, 0.0, 1.0))
        im.PushStyleColor2(im.Col_FrameBgActive, im.ImVec4(0.0, 0.0, 0.0, 1.0))
        im.PushStyleColor2(im.Col_ButtonActive, im.ImVec4(0.0, 0.0, 0.0, 1.0))
        im.PushStyleColor2(im.Col_ButtonHovered, im.ImVec4(0.0, 0.0, 0.0, 1.0))
        im.PushStyleColor2(im.Col_FrameBgHovered, im.ImVec4(0.0, 0.0, 0.0, 1.0))
        im.PushStyleColor2(im.Col_TitleBgCollapsed, im.ImVec4(0.0, 0.0, 0.0, 0.0))
    end
end
setThemeDark()

local function lightEnabled(group, lightVal)
    if group then
        for i = 0, group.obj:getCount(), 1 do
            scenetree.findObjectById(group.obj:idAt(i)).isEnabled = lightVal
        end
    end
end

local function lightShadows(group, shadowVal)
    if group then
        for i = 0, group.obj:getCount(), 1 do
            scenetree.findObjectById(group.obj:idAt(i)).castShadows = shadowVal
        end
    end
end

local function dropSize(group, f, o)
    if group then
        for i = 0, group.obj:getCount(), 1 do
            scenetree.findObjectById(group.obj:idAt(i)).dropSize = ((o * f * 0.5) + (o * 0.5))
        end
    end
end

local function nightColor(f, b)
    sunsky = scenetree.sunsky
    clouds = scenetree.clouds
    local c = (0.85 * f) + 0.15
    if isRain then dropSize(scenetree.Rain, f, 0.7)
    elseif isSnow then dropSize(scenetree.Snow, f, 1.5)
    end

    if sunsky then
        sunsky.logWeight = (0.09 * f) + 0.9
        core_environment.setNightGradientFile("")
        sunsky.nightColor = Point4F(b, b, b, 1.0)
    end
    if clouds then
        clouds.baseColor = Point4F(c, c, c, 1.0)
    end
end

local function nightValues(tod, lightVal, shadowVal, bright)
    if not tod then return end
    local LRPFX = scenetree.findObject("LightRayPostFX")
    local sunsky_obj = scenetree.sunsky
    local time = tod.time
    local frac

    if time > 0.25 and time < 0.75 then -- is Night
        if LRPFX then LRPFX.isEnabled = false end
        lightEnabled(scenetree.Spotlights, lightVal)
        lightEnabled(scenetree.Pointlights, lightVal)
        lightShadows(scenetree.Spotlights, shadowVal)
        if sunsky_obj then sunsky_obj.castShadows = false end
    else
        if LRPFX then LRPFX.isEnabled = userRaysEnabled end
        lightEnabled(scenetree.Spotlights, false)
        lightEnabled(scenetree.Pointlights, false)
        if sunsky_obj then sunsky_obj.castShadows = not (isRain ~= nil and isRain) end
    end

    if time <= 0.20 or time >= 0.80 then frac = 1.0
    elseif time >= 0.3 and time <= 0.7 then frac = 0.0
    elseif time > 0.20 and time < 0.30 then frac = (0.30 - time) / 0.1
    elseif time > 0.70 and time < 0.80 then frac = (0.70 - time) / -0.1
    end
    nightColor(frac, bright)
end

local function getWeather()
    theLevelInfo = scenetree.theLevelInfo
    if isRain == nil and isSnow == nil then 
        isRain = scenetree.techeyyRain
        isSnow = scenetree.techeyySnow 
    end
    if isRain then
        if theLevelInfo and tostring(theLevelInfo.globalEnviromentMap) ~= cubemapname then 
            theLevelInfo:setField('globalEnviromentMap', 0, cubemapname) 
            theLevelInfo:postApply() 
        end
    end
end

local function drawBeginWindow()
    sunsky = scenetree.sunsky

    if skipImgui then return end

    if im.Begin("Night Control", showUI, im.WindowFlags_AlwaysAutoResize) then
        if im.IsItemHovered() then im.BeginTooltip() im.Text("Use ALT+U to toggle UI") im.EndTooltip() end
        im.PushItemWidth(170)

        if im.SliderFloat("##Light", brightSlider, 1, 10, "Night Brightness: %.0f0%%") then if sunsky and sunsky.postApply then sunsky:postApply() end end

        if im.Button("   Cycle Night Cubemap   ") then
            if sunsky and sunsky:getField('nightCubemap', 0) ~= "BlackSkyCubemap" then 
                sunsky:setField('nightCubemap', 0, "BlackSkyCubemap") 
            else 
                if sunsky then sunsky:setField('nightCubemap', 0, "nightCubemap") end
            end
            if sunsky and sunsky.postApply then sunsky:postApply() end
        end

        if im.IsItemHovered() then im.BeginTooltip() im.Text("Recommended for lower brightness") im.EndTooltip() end

        im.PushItemWidth(90)
        im.Text("Streetlights:") im.SameLine()
        if im.SliderFloat("##Light2", streetlightSlider, 1, 3, "%.0f") then if sunsky and sunsky.postApply then sunsky:postApply() end end
        
        if streetlightSlider[0] == 1 then lightVal = false shadowVal = false streetlightSliderHovered = "Streetlights OFF"
        elseif streetlightSlider[0] == 2 then lightVal = true shadowVal = false streetlightSliderHovered = "Streetlights WITHOUT shadows"
        elseif streetlightSlider[0] == 3 then lightVal = true shadowVal = true streetlightSliderHovered = "Streetlights WITH shadows" end
        if im.IsItemHovered() then im.BeginTooltip() im.Text(streetlightSliderHovered) im.EndTooltip() end

    end
    im.End()
end

local function onUiChangedState(newUIState, prevUIState)
    if newUIState and newUIState:sub(1,4) == 'menu' then
        skipImgui = false
    else
        skipImgui = true
    end

    if newUIState and newUIState:sub(1,4) == 'fade' then
        fadeScreenRunning = true
    else
        fadeScreenRunning = false
    end
end

local function onUpdate()
    tod = scenetree.tod
    getWeather()
    if not skipImgui then
        drawBeginWindow()
    end
    if tod then nightValues(tod, lightVal, shadowVal, brightSlider[0] / 7.5) end
end

local function onExtensionLoaded()
    -- initialize gui wrapper if it exists
    if gui_module and gui_module.initialize then
        pcall(function() gui_module.initialize(gui) end)
    end
    -- register our window with gui module if available (optional)
    if gui and gui.registerWindow then
        pcall(function()
            gui.registerWindow(wndName, im.ImVec2(0, 0), im.ImVec2(200, 200), true)
            gui.setWindowVisibility(wndName, true)
        end)
    end

end

local function onEditorInitialized()
    if editor and editor.addWindowMenuItem then
        editor.addWindowMenuItem("Night Control", function() end, {groupMenuName = 'Map Addons'})
    end
end

M.onExtensionLoaded = onExtensionLoaded
M.onUpdate = onUpdate
M.onUiChangedState = onUiChangedState
M.onEditorInitialized = onEditorInitialized

return M
