wheelWindow = nil
wheelOfDestinyWindow = nil
gemAtelierWindow = nil
fragmentWindow = nil
newPresetWindow = nil
renamePresetWindow = nil
exportCodeWindow = nil
deletePresetWindow = nil
checkSavePresetWindow = nil
selectedNewPresetRadio = nil
local summaryVisible = false

wheelPanel = nil
centerReferencePoint = nil

if not SkillwheelStringsLibrary then
  SkillwheelStringsLibrary = {}
end

WheelOfDestiny = WheelOfDestiny or {}
GemAtelier     = GemAtelier     or {}
Workshop       = Workshop       or {}

-- ===== MISSING CIPSOFT API STUBS / SAFETY =====
function WheelOfDestiny.onNewPresetSelectionChange(widget) end
function WheelOfDestiny.loadWheelPresets() end
function WheelOfDestiny.onDestinyWheel(...) end
function WheelOfDestiny.onUnlockGem(...) end
function WheelOfDestiny.onRemoveClick() end
function WheelOfDestiny.saveWheelPresets() end
function WheelOfDestiny.onWheelClick(position) end
function WheelOfDestiny.onMouseMove(widget, mousePos) end
function WheelOfDestiny.configurePresets() end
function WheelOfDestiny.configureSummary() end
function WheelOfDestiny.onGemVesselClick(domain) end

function GemAtelier.onUnlockGem(...) end
function GemAtelier.resetFields() end
function GemAtelier.showGems(force) end

function Workshop.createFragments() end
function Workshop.showFragmentList(force) end

function onAddOne() end
function onRmvOne() end

-- Resource ids fallback (so g_game.requestResource() won’t crash if constants don’t exist)
ResourceBank           = ResourceBank           or 1
ResourceInventary      = ResourceInventary      or 2
ResourceWheelPoints    = ResourceWheelPoints    or 3
ResourceLesserGem      = ResourceLesserGem      or 4
ResourceRegularGem     = ResourceRegularGem     or 5
ResourceGreaterGem     = ResourceGreaterGem     or 6
ResourceLesserFragment = ResourceLesserFragment or 7
ResourceGreaterFragment= ResourceGreaterFragment or 8

local function getUiParent()
  -- safest parent in OTC
  if modules and modules.game_interface and modules.game_interface.getRootPanel then
    local p = modules.game_interface.getRootPanel()
    if p then return p end
  end
  return rootWidget
end

function init()
  local parent = getUiParent()
  if not parent then
    error("UI parent not available (rootWidget nil)")
    return
  end

  -- IMPORTANT: load UI as a widget instance
  wheelWindow = g_ui.loadUI('wheel.otui', parent)
  if not wheelWindow then
    error('wheel.otui root widget not loaded')
    return
  end

  mainPanel = wheelWindow:getChildById('mainPanel')
  if not mainPanel then
    error('mainPanel not found in wheel.otui')
    return
  end

  -- Wheel Menu
  wheelOfDestinyWindow = g_ui.loadUI('styles/wheelMenu', mainPanel)
  if wheelOfDestinyWindow then wheelOfDestinyWindow:hide() end

  -- Gem Menu
  gemAtelierWindow = g_ui.loadUI('styles/gemMenu', mainPanel)
  if gemAtelierWindow then gemAtelierWindow:hide() end

  -- Fragment Menu
  fragmentWindow = g_ui.loadUI('styles/fragmentMenu', mainPanel)
  if fragmentWindow then fragmentWindow:hide() end

  -- New Preset Menu
  newPresetWindow = g_ui.loadUI('styles/newPreset', parent)
  if newPresetWindow then newPresetWindow:hide() end

  -- Rename Preset Window
  renamePresetWindow = g_ui.loadUI('styles/renamePreset', parent)
  if renamePresetWindow then renamePresetWindow:hide() end

  loadConfigJson()

  -- Radio group safety
  if newPresetWindow and newPresetWindow.contentPanel then
    selectedNewPresetRadio = UIRadioGroup.create()
    if newPresetWindow.contentPanel.useEmpty then selectedNewPresetRadio:addWidget(newPresetWindow.contentPanel.useEmpty) end
    if newPresetWindow.contentPanel.copyPreset then selectedNewPresetRadio:addWidget(newPresetWindow.contentPanel.copyPreset) end
    if newPresetWindow.contentPanel.import then
      selectedNewPresetRadio:addWidget(newPresetWindow.contentPanel.import)
      selectedNewPresetRadio:selectWidget(newPresetWindow.contentPanel.import)
    end
    selectedNewPresetRadio.onSelectionChange = WheelOfDestiny.onNewPresetSelectionChange
  end

  -- Buttons safety
  if wheelOfDestinyWindow then
    local addOneButton = wheelOfDestinyWindow:recursiveGetChildById('addOne')
    local rmvOneButton = wheelOfDestinyWindow:recursiveGetChildById('rmvOne')

    if addOneButton then
      g_mouse.bindAutoPress(addOneButton, function() onAddOne() end, 500, nil)
    end
    if rmvOneButton then
      g_mouse.bindAutoPress(rmvOneButton, function() onRmvOne() end, 500, nil)
    end
  end

  loadMenu('wheelMenu')
  toggleTabBarButtons('informationButton')
  hide()

  connect(g_game, {
    onGameEnd = onGameEnd,
    onGameStart = WheelOfDestiny.loadWheelPresets,
    onDestinyWheel = WheelOfDestiny.onDestinyWheel,
    onUnlockGem = GemAtelier.onUnlockGem,
    onResourceBalance = onResourceBalance,
  })
end

function terminate()
  disconnect(g_game, {
    onGameEnd = onGameEnd,
    onGameStart = WheelOfDestiny.loadWheelPresets,
    onDestinyWheel = WheelOfDestiny.onDestinyWheel,
    onUnlockGem = GemAtelier.onUnlockGem,
    onResourceBalance = onResourceBalance
  })

  if wheelWindow then
    wheelWindow:destroy()
    wheelWindow = nil
  end

  -- clean auxiliary windows if they exist
  if newPresetWindow then newPresetWindow:destroy(); newPresetWindow = nil end
  if renamePresetWindow then renamePresetWindow:destroy(); renamePresetWindow = nil end
  if exportCodeWindow then exportCodeWindow:destroy(); exportCodeWindow = nil end
  if deletePresetWindow then deletePresetWindow:destroy(); deletePresetWindow = nil end
  if checkSavePresetWindow then checkSavePresetWindow:destroy(); checkSavePresetWindow = nil end
end

function toggle()
  if not wheelWindow then return end

  if wheelWindow:isVisible() then
    wheelWindow:hide()
    if g_ui and g_ui.setInputLockWidget then
		g_ui.setInputLockWidget(nil)
	end
  else
    wheelWindow:show()
    wheelWindow:raise()
    wheelWindow:focus()

    loadMenu('wheelMenu')

    -- hide other windows
    if gemAtelierWindow and gemAtelierWindow:isVisible() then gemAtelierWindow:hide() end
    if fragmentWindow and fragmentWindow:isVisible() then fragmentWindow:hide() end

    if g_game and g_game.getLocalPlayer and g_game.sendOpenDestinyWheel then
      local lp = g_game.getLocalPlayer()
      if lp then g_game.sendOpenDestinyWheel(lp:getId()) end
    end

    local tab = wheelWindow:recursiveGetChildById('tabContent')
    if tab then tab:setVisible(false) end

    WheelOfDestiny.onRemoveClick()
  end
end

function hide()
  if g_ui and g_ui.setInputLockWidget then
    g_ui.setInputLockWidget(nil)
  end
  if wheelWindow then
    wheelWindow:hide()
  end
end

function onGameEnd()
  hide()
  WheelOfDestiny.saveWheelPresets()

  if newPresetWindow then newPresetWindow:hide() end
  if renamePresetWindow then renamePresetWindow:hide() end

  if exportCodeWindow then exportCodeWindow:destroy(); exportCodeWindow = nil end
  if checkSavePresetWindow then checkSavePresetWindow:destroy(); checkSavePresetWindow = nil end

  WheelOfDestiny.currentPreset = {}
  g_ui.setInputLockWidget(nil)
end

function show()
  if g_game and g_game.requestResource then
    g_game.requestResource(ResourceBank)
    g_game.requestResource(ResourceInventary)
    g_game.requestResource(ResourceWheelPoints)
    g_game.requestResource(ResourceLesserGem)
    g_game.requestResource(ResourceRegularGem)
    g_game.requestResource(ResourceGreaterGem)
  end

  if g_game and g_game.getLocalPlayer and g_game.sendOpenDestinyWheel then
    local lp = g_game.getLocalPlayer()
    if lp then g_game.sendOpenDestinyWheel(lp:getId()) end
  end
end

-- check click point
function onWheelClick(position)
  WheelOfDestiny.onWheelClick(position)
end

function loadMenu(menuId)
  if wheelOfDestinyWindow and wheelOfDestinyWindow:isVisible() then wheelOfDestinyWindow:hide() end
  if gemAtelierWindow and gemAtelierWindow:isVisible() then gemAtelierWindow:hide() end
  if newPresetWindow and newPresetWindow:isVisible() then newPresetWindow:hide() end
  if fragmentWindow and fragmentWindow:isVisible() then fragmentWindow:hide() end

  if not wheelWindow then return end

  local wheelMenuButton = wheelWindow.optionsTabBar and wheelWindow.optionsTabBar:getChildById('wheelMenu')
  local gemMenuButton = wheelWindow.optionsTabBar and wheelWindow.optionsTabBar:getChildById('gemMenu')
  local fragmentMenuButton = wheelWindow.optionsTabBar and wheelWindow.optionsTabBar:getChildById('fragmentMenu')

  if menuId == 'wheelMenu' then
    if gemAtelierWindow then gemAtelierWindow:hide() end
    if fragmentWindow then fragmentWindow:hide() end

    if wheelOfDestinyWindow then
      wheelPanel = wheelOfDestinyWindow:getChildById('wheelPanel')
      if wheelPanel then
        wheelPanel.onMouseMove = WheelOfDestiny.onMouseMove
      end

      centerReferencePoint = wheelOfDestinyWindow:recursiveGetChildById('centerReferencePoint')
      if wheelMenuButton then wheelMenuButton:setChecked(true) end
      if gemMenuButton then gemMenuButton:setChecked(false) end
      if fragmentMenuButton then fragmentMenuButton:setChecked(false) end

      -- These paths may differ; guard them.
      local informationButton = wheelWindow:recursiveGetChildById('informationButton')
      local managePresetsButton = wheelWindow:recursiveGetChildById('managePresetsButton')
      local summaryButton = wheelWindow:recursiveGetChildById('summaryButton')

      if informationButton then informationButton.onClick = function() toggleTabBarButtons('informationButton') end end
      if managePresetsButton then
        managePresetsButton.onClick = function()
          toggleTabBarButtons('managePresetsButton')
          WheelOfDestiny.configurePresets()
        end
      end
      if summaryButton then
        summaryButton.onClick = function() toggleSummary() end
      end

      toggleTabBarButtons('informationButton')

      if WheelOfDestiny.lastSelectedGemVessel and WheelOfDestiny.lastSelectedGemVessel:isVisible() then
        local currentDomain = WheelOfDestiny.lastSelectedGemVessel:getId():gsub("selectVessel", "")
        WheelOfDestiny.onGemVesselClick(tonumber(currentDomain))
      end

      Workshop.createFragments()
      wheelOfDestinyWindow:show(true)
    end

  elseif menuId == 'gemMenu' then
    Workshop.createFragments()
    GemAtelier.resetFields()
    GemAtelier.showGems(true)
    if gemAtelierWindow then gemAtelierWindow:show(true) end
    if wheelMenuButton then wheelMenuButton:setChecked(false) end
    if fragmentMenuButton then fragmentMenuButton:setChecked(false) end
    if gemMenuButton then gemMenuButton:setChecked(true) end

  elseif menuId == 'fragmentMenu' then
    Workshop.createFragments()
    Workshop.showFragmentList(true)
    if fragmentWindow then fragmentWindow:show(true) end
    if wheelMenuButton then wheelMenuButton:setChecked(false) end
    if gemMenuButton then gemMenuButton:setChecked(false) end
    if fragmentMenuButton then fragmentMenuButton:setChecked(true) end
  end
end

function toggleSummary()
  summaryVisible = not summaryVisible
  if not wheelWindow then return end

  local summaryPanel = wheelWindow:recursiveGetChildById('summary')
  local dedicationPerksPanel = wheelWindow:recursiveGetChildById('dedicationPerks')
  local convictionPerksPanel = wheelWindow:recursiveGetChildById('convictionPerks')
  local vesselsPanel = wheelWindow:recursiveGetChildById('vessels')
  local revelationPerksPanel = wheelWindow:recursiveGetChildById('revelationPerks')

  if summaryPanel then summaryPanel:setVisible(summaryVisible) end
  if dedicationPerksPanel then dedicationPerksPanel:setVisible(not summaryVisible) end
  if convictionPerksPanel then convictionPerksPanel:setVisible(not summaryVisible) end
  if vesselsPanel then vesselsPanel:setVisible(not summaryVisible) end
  if revelationPerksPanel then revelationPerksPanel:setVisible(not summaryVisible) end

  WheelOfDestiny.configureSummary()
end

function toggleTabBarButtons(selectedButtonId)
  if not wheelWindow then return end

  -- These exact paths may differ; use recursive lookup for safety
  local informationButton = wheelWindow:recursiveGetChildById('informationButton')
  local managePresetsButton = wheelWindow:recursiveGetChildById('managePresetsButton')
  local tabContent = wheelWindow:recursiveGetChildById('tabContent')

  if not informationButton or not managePresetsButton or not tabContent then
    return
  end

  local managePanel = tabContent:getChildById('manage')
  local infoPanel = tabContent:getChildById('information')

  if selectedButtonId == 'informationButton' then
    informationButton:setSize(tosize("174 34"))
    informationButton:setImageSource('/images/game/destiny_wheel/informationSelection')
    informationButton:setImageClip(torect("0 0 174 34"))
    managePresetsButton:setSize(tosize("34 34"))
    managePresetsButton:setImageSource('/images/game/destiny_wheel/small_manage_button')
    managePresetsButton:setImageClip(torect("0 0 34 34"))
    if managePanel then managePanel:setVisible(false) end
    if infoPanel then infoPanel:setVisible(true) end

  elseif selectedButtonId == 'managePresetsButton' then
    informationButton:setSize(tosize("34 34"))
    informationButton:setImageSource('/images/game/destiny_wheel/small_information_button')
    informationButton:setImageClip(torect("0 0 34 34"))
    managePresetsButton:setSize(tosize("174 34"))
    managePresetsButton:setImageSource('/images/game/destiny_wheel/manageSelect')
    managePresetsButton:setImageClip(torect("0 0 174 34"))
    if infoPanel then infoPanel:setVisible(false) end
    if managePanel then managePanel:setVisible(true) end
  end
end

function onResourceBalance()
  if not wheelWindow or not wheelWindow:isVisible() then
    return true
  end

  local player = g_game.getLocalPlayer and g_game.getLocalPlayer()
  if not player or not player.getResourceValue then
    return true
  end

  local bankMoney = player:getResourceValue(ResourceBank) or 0
  local characterMoney = player:getResourceValue(ResourceInventary) or 0
  local lesserFragment = player:getResourceValue(ResourceLesserFragment) or 0
  local greaterFragment = player:getResourceValue(ResourceGreaterFragment) or 0

  local value = bankMoney + characterMoney

  if wheelWindow.moneyPanel and wheelWindow.moneyPanel.gold then
    wheelWindow.moneyPanel.gold:setText(tostring(value))
  end
  if wheelWindow.lesserFragmentPanel and wheelWindow.lesserFragmentPanel.gold then
    wheelWindow.lesserFragmentPanel.gold:setText(tostring(lesserFragment))
  end
  if wheelWindow.greaterFragmentPanel and wheelWindow.greaterFragmentPanel.gold then
    wheelWindow.greaterFragmentPanel.gold:setText(tostring(greaterFragment))
  end

  return true
end

function loadConfigJson()
  local file = "/json/SkillwheelStringsJsonLibrary.json"
  if g_resources.fileExists(file) then
    local status, result = pcall(function()
      return json.decode(g_resources.readFileContents(file))
    end)

    if not status then
      return g_logger.error("Error while reading characterdata file. Details: " .. result)
    end

    SkillwheelStringsLibrary = result
  end
end
