lootsplitter = nil
advancedOptions = nil
advancedConfig = {}

function init()
  lootsplitter = g_ui.displayUI('/game_lootsplitter/lootsplitter')
  lootsplitter:hide()
  advancedOptions = g_ui.loadUI('advanced', g_ui.getRootWidget())
  advancedOptions:hide()
end

function terminate()
  if lootsplitter then
      lootsplitter:destroy()
      lootsplitter = nil
  end
end

function toggle()
  if lootsplitter:isVisible() then
      lootsplitter:hide()
  else
      lootsplitter:show()
  end
end

function show()
  lootsplitter:show()
end

function hide()
  lootsplitter:hide()
end

local function round(num, numDecimalPlaces)
  local mult = 10^(numDecimalPlaces or 0)
  return math.floor(num * mult + 0.5) / mult
end

local function formatNumber(num)
  num = round(num, 0)
  local formatted = tostring(num)
  while true do
      formatted, k = string.gsub(formatted, "^(-?%d+)(%d%d%d)", '%1.%2')
      if k == 0 then
          break
      end
  end
  return formatted
end

local function parseNumericValue(numericValue)
  numericValue = string.gsub(numericValue, "[^%d,%-]", "")
  numericValue = string.gsub(numericValue, ",", "")
  local num = tonumber(numericValue)
  if num == nil then
      error("Error processing numeric value: " .. numericValue)
  end
  return num
end

local function extractPlayerData(data, step)
  local players = {}
  local totalBalance = 0
  local numPlayers = 0

  local leaderPattern = "([%a%s'%-]+%s*%(Leader%)?)%s*Loot:%s*([%d%,]+)%s*Supplies:%s*([%d%,]+)%s*Balance:%s*([%d%,%-]+)%s*Damage:%s*[%d%,]+%s*Healing:%s*[%d%,]+"
  local playerPattern = "([%a%s'%-]+)%s*Loot:%s*([%d%,]+)%s*Supplies:%s*([%d%,]+)%s*Balance:%s*([%d%,%-]+)%s*Damage:%s*[%d%,]+%s*Healing:%s*[%d%,]+"

  local playerConfig = nil
  local leaderName, leaderLoot, leaderSupplies, leaderBalance = data:match(leaderPattern)
  if leaderName then
    local cleanLeaderName = leaderName:gsub("%s*%b()", ""):match("^%s*(.-)%s*$")
    local leaderBalanceValue = parseNumericValue(leaderBalance)

    totalBalance = totalBalance + leaderBalanceValue

    local extraCost = 0
    local isRemoved = false
    if step == 2 then
      playerConfig = getAdvancedConfig(cleanLeaderName)
      extraCost = playerConfig and playerConfig.ExtraCost or 0
      isRemoved = (playerConfig and playerConfig.isRemoved ~= nil) and playerConfig.isRemoved or false
      leaderBalanceValue = leaderBalanceValue - extraCost
      totalBalance = totalBalance - extraCost
    end

    if step == 1 or (step == 2 and not isRemoved) then
      numPlayers = numPlayers + 1

      table.insert(players, {
          Name = cleanLeaderName,
          Loot = parseNumericValue(leaderLoot),
          Supplies = parseNumericValue(leaderSupplies),
          Balance = leaderBalanceValue,
          isLeader = true
      })
    end
  end

  local remainingData = data:gsub(leaderPattern, "")
  for name, loot, supplies, balance in remainingData:gmatch(playerPattern) do
    local cleanName = name:gsub("%s*%b()", ""):match("^%s*(.-)%s*$")
    local balanceValue = parseNumericValue(balance)

    totalBalance = totalBalance + balanceValue

    local extraCost = 0
    local isRemoved = false
    if step == 2 then
      playerConfig = getAdvancedConfig(cleanName)
      extraCost = playerConfig and playerConfig.ExtraCost or 0
      isRemoved = (playerConfig and playerConfig.isRemoved ~= nil) and playerConfig.isRemoved or false
      balanceValue = balanceValue - extraCost
      totalBalance = totalBalance - extraCost
    end

    if step == 1 or (step == 2 and not isRemoved) then
      numPlayers = numPlayers + 1

      table.insert(players, {
          Name = cleanName,
          Loot = parseNumericValue(loot),
          Supplies = parseNumericValue(supplies),
          Balance = balanceValue,
          isLeader = false
      })
    end
  end

  return players, totalBalance, numPlayers
end

function processLootMessage(message)
  local sessionData = message:match("Session data:%s*(.-)%s*$")
  if not sessionData then
      return
  end

   local players, totalBalance, numPlayers = extractPlayerData(sessionData, 1)
   local playersListWidget = advancedOptions.contentPanel:getChildById('playersList')
   playersListWidget:destroyChildren()
   for _, player in ipairs(players) do
     addPlayerToList(player)
   end

  local players, totalBalance, numPlayers = extractPlayerData(sessionData, 2)
  if numPlayers == 0 then
      return
  end

  local averageProfit = totalBalance / numPlayers
  local transfers = {}
  local debtors = {}
  local creditors = {}

  for _, player in ipairs(players) do
      local profitDifference = player.Balance - averageProfit
      if profitDifference > 0 then
          table.insert(creditors, {Name = player.Name, Amount = profitDifference})
      elseif profitDifference < 0 then
          table.insert(debtors, {Name = player.Name, Amount = -profitDifference})
      end
  end

  local transferLog = ""
  for _, debtor in ipairs(debtors) do
      for _, creditor in ipairs(creditors) do
          local transferAmount = math.floor(math.min(debtor.Amount, creditor.Amount))
          if transferAmount > 0 then
              transferLog = transferLog .. string.format(
                  "- %s should transfer %s to %s\n",
                  creditor.Name, transferAmount, debtor.Name
              )

              debtor.Amount = debtor.Amount - transferAmount
              creditor.Amount = creditor.Amount - transferAmount

              if debtor.Amount <= 0 then break end
          end
      end
  end

  local resultLogContent = lootsplitter.contentPanel:getChildById('resultLogContent')
  local resultText = string.format(
      "- Loot Splitter -\n"
  )

  resultText = resultText .. "\n- Bank transfers:\n"
  resultText = resultText .. (transferLog ~= "" and transferLog or "No transfers needed.\n")

  resultText = resultText .. string.format(
      "\n- Total profit: %s $ (%s $ each)",
      formatNumber(totalBalance), formatNumber(averageProfit)
  )

  resultLogContent:setText(resultText)
  lootsplitter.fullResultText = resultText
end

function copyResultText()
  if lootsplitter.fullResultText then
      g_window.setClipboardText(lootsplitter.fullResultText)
  end
end

function onGenerateButtonClick()
  local message = lootsplitter.contentPanel:getChildById('huntLogContent'):getText()
  processLootMessage(message)
end

function showAdvancedOptions()
  lootsplitter:hide()
  advancedOptions:show()
end

function getAdvancedConfig(playerName)
  for _, playerData in pairs(advancedConfig) do
    if playerData.Name == playerName then
      return playerData
    end
  end
  return nil
end

function updateAdvancedConfigs(playerData)
  local playerExists = false
  for _, playerConfig in pairs(advancedConfig) do
    if playerConfig.Name == playerData.Name then
      playerConfig.Supplies = playerData.Supplies
      playerConfig.Balance = playerData.Balance
      playerConfig.Loot = playerData.Loot
      playerConfig.ExtraCost = playerData.ExtraCost
      playerConfig.isRemoved = playerData.isRemoved
      playerExists = true
    end
  end
  if not playerExists then
    table.insert(advancedConfig, playerData)
  end
end

function addPlayerToList(playerData)
  local playerWidget = g_ui.createWidget('PlayerOptionInfo', advancedOptions.contentPanel:getChildById('playersList'))

  local playerNameLabel = playerWidget:getChildById('playerNameLabel')
  playerNameLabel:setText(playerData.Name)

  local playerConfig = getAdvancedConfig(playerData.Name)

  local extraCostText = playerWidget:getChildById('extraCostText')
  if extraCostText then
    if playerConfig and playerConfig.ExtraCost then
      extraCostText:setText(playerConfig.ExtraCost)
    end

    extraCostText.onTextChange = function(widget)
      playerData.ExtraCost = tonumber(widget:getText()) or 0
      updateAdvancedConfigs(playerData)
    end
  end

  local removePlayerCheck = playerWidget:getChildById('removePlayer')
  if removePlayerCheck then
    if playerConfig then
      removePlayerCheck:setChecked(playerConfig.isRemoved)
      if removePlayerCheck:isChecked() then
        for _, child in ipairs(playerWidget:getChildren()) do
          if child ~= removePlayerCheck then
            child:setEnabled(false)
          end
        end
      end
    end
    removePlayerCheck.onCheckChange = function(widget)
      if widget:isChecked() then
        for _, child in ipairs(playerWidget:getChildren()) do
          if child ~= removePlayerCheck then
            child:setEnabled(false)
          end
        end
        playerData.isRemoved = true
      else
        for _, child in ipairs(playerWidget:getChildren()) do
          if child ~= removePlayerCheck then
            child:setEnabled(true)
          end
        end
        playerData.isRemoved = false
      end
      updateAdvancedConfigs(playerData)
    end
  end
end

function applyChanges()
  advancedOptions:hide() 
  lootsplitter:show()
  onGenerateButtonClick()
end