local OPCODE = 202
local window
local button
local current = {}

local function captureKeyboard()
  if not window then return end
  window:grabKeyboard()
  window.onKeyDown = function(_, keyCode, keyboardModifiers)
    if keyboardModifiers == KeyboardNoModifier and keyCode == KeyEscape then
      toggle()
    end
    return true
  end
end

local function releaseKeyboard()
  if window then window:ungrabKeyboard() end
end

local function send(action, data)
  local protocol = g_game.getProtocolGame()
  if protocol and g_game.getFeature(GameExtendedOpcode) then
    protocol:sendExtendedJSONOpcode(OPCODE, {action=action,data=data or {}})
  end
end

local function setText(id, value)
  local widget = window and window:recursiveGetChildById(id)
  if widget then widget:setText(tostring(value)) end
end

local function refresh(data)
  current = data or {}
  setText('pointsValue', string.format('%d / %d', current.points or 0, current.maxPoints or 400))
  setText('unspentValue', current.unspent or 0)
  setText('tokensValue', current.tokens or 0)
  setText('mightRank', string.format('%d / %d', current.might or 0, current.maxBranch or 100))
  setText('arcanaRank', string.format('%d / %d', current.arcana or 0, current.maxBranch or 100))
  setText('vitalityRank', string.format('%d / %d', current.vitality or 0, current.maxBranch or 100))
  setText('regenerationRank', string.format('%d / %d', current.regeneration or 0, current.maxBranch or 100))
  local b = current.bonuses or {}
  setText('mightBonus', string.format('+%.1f%% physical strength', b.might or 0))
  setText('arcanaBonus', string.format('+%.1f%% magic/healing, +%.1f%% mana', b.arcana or 0, b.mana or 0))
  setText('vitalityBonus', string.format('+%.1f%% health, +%.1f%% shielding', b.health or 0, b.shielding or 0))
  setText('regenerationBonus', string.format('+%.1f%% HP and mana regeneration', b.regeneration or 0))
end

local function onOpcode(protocol, opcode, payload)
  if payload.action == 'sync' then refresh(payload.data)
  -- Rift Core feedback is sent by the server to Server Log. Do not block play
  -- with an OK dialog (in particular after consuming a Rift Stone).
  elseif payload.action == 'message' then return end
end

function init()
  window = g_ui.displayUI('riftcore')
  window:hide()
  button = modules.client_topmenu.addRightGameButton('riftCoreButton', 'Rift Core', '/images/topbuttons/riftcore', toggle, false, 5)
  button:setSize({width=20,height=20})
  ProtocolGame.registerExtendedJSONOpcode(OPCODE, onOpcode)
  connect(g_game, {onGameStart=online,onGameEnd=offline})
  if g_game.isOnline() then online() end
end

function terminate()
  disconnect(g_game, {onGameStart=online,onGameEnd=offline})
  ProtocolGame.unregisterExtendedJSONOpcode(OPCODE, onOpcode)
  if button then button:destroy(); button=nil end
  releaseKeyboard()
  if window then window:destroy(); window=nil end
end

function online() scheduleEvent(function() send('init') end, 500) end
function offline() releaseKeyboard(); if window then window:hide() end end
function toggle()
  if not window then return end
  if window:isVisible() then
    releaseKeyboard()
    window:hide()
  else
    window:show()
    window:raise()
    window:focus()
    captureKeyboard()
    send('init')
  end
end
function allocate(branch)
  local names = {might='Might', arcana='Arcana', vitality='Vitality', regeneration='Regeneration'}
  local box
  local confirm = function()
    send('allocate', {branch=branch})
    if box then box:destroy(); box=nil end
  end
  local cancel = function()
    if box then box:destroy(); box=nil end
  end
  box = displayGeneralBox('Allocate Rift Point', 'Are you sure you want to add 1 point to ' .. (names[branch] or branch) .. '?', {
    {text='Add Point', callback=confirm}, {text='Cancel', callback=cancel}, anchor=AnchorHorizontalCenter
  }, confirm, cancel)
end
function resetBuild()
  local box
  local confirm = function()
    send('reset')
    if box then box:destroy(); box=nil end
  end
  local cancel = function()
    if box then box:destroy(); box=nil end
  end
  box = displayGeneralBox('Reset Rift Core', 'Reset all allocated points for exactly 50 Repera Tokens?', {
    {text='Reset', callback=confirm}, {text='Cancel', callback=cancel}, anchor=AnchorHorizontalCenter
  }, confirm, cancel)
end
