local context = G.botContext
local Panels = context.Panels

Panels.Looting = function(parent)
  local ui = context.setupUI([[
Panel
  id: looting
  height: 180

  BotLabel
    anchors.top: parent.top
    anchors.left: parent.left
    anchors.right: parent.right
    text: Looting

  ComboBox
    id: config
    anchors.top: prev.bottom
    anchors.left: parent.left
    margin-top: 5
    text-offset: 3 0
    width: 130

  Button
    id: enableButton
    anchors.top: prev.top
    anchors.left: prev.right
    anchors.right: parent.right
    margin-left: 5

  Button
    margin-top: 1
    id: add
    anchors.top: prev.bottom
    anchors.left: parent.left
    text: Add
    width: 60
    height: 17

  Button
    id: edit
    anchors.top: prev.top
    anchors.horizontalCenter: parent.horizontalCenter
    text: Edit
    width: 60
    height: 17

  Button
    id: remove
    anchors.top: prev.top
    anchors.right: parent.right
    text: Remove
    width: 60
    height: 17

  ScrollablePanel
    id: items
    anchors.top: prev.bottom
    anchors.right: parent.right
    anchors.left: parent.left
    vertical-scrollbar: scrollBar
    margin-right: 5
    margin-top: 2
    height: 70
    layout:
      type: grid
      cell-size: 34 34
      flow: true

  BotSmallScrollBar
    id: scrollBar
    anchors.top: prev.top
    anchors.bottom: prev.bottom
    anchors.right: parent.right
    step: 10
    pixels-scroll: true

  BotLabel
    anchors.top: prev.bottom
    anchors.left: parent.left
    anchors.right: parent.right
    margin-top: 4
    text: Loot Containers

  ItemsRow
    id: containers
    anchors.top: prev.bottom
    anchors.left: parent.left
    anchors.right: parent.right
    height: 33
    margin-top: 2

]], parent)

  local lootContainers = { ui.containers.item1, ui.containers.item2, ui.containers.item3, ui.containers.item4, ui.containers.item5 }

  if type(context.storage.looting) ~= "table" then
    context.storage.looting = {}
  end
  if type(context.storage.looting.configs) ~= "table" then
    context.storage.looting.configs = {}
  end

  local getConfigName = function(config)
    local matches = regexMatch(config, [[name:\s*([^\n]*)$]])
    if matches[1] and matches[1][2] then
      return matches[1][2]:trim()
    end
    return nil
  end

  local items = {}
  local itemsByKey = {}
  local containers = {}
  local commands = {}
  local refreshConfig = nil -- declared later

  local createNewConfig = function(focusedWidget)
    if not context.storage.looting.activeConfig or not context.storage.looting.configs[context.storage.looting.activeConfig] then
      return
    end

    local tmpItems = {}
    local tmpContainers = {}
    local focusIndex = 0

    local newConfig = ""
    for i, text in ipairs(commands) do
      newConfig = newConfig .. text .. "\n"
    end
    for i=1,ui.items:getChildCount() do
      local widget = ui.items:getChildByIndex(i)
      if widget and widget:getItemId() >= 100 then
        if tmpItems[widget:getItemId()] == nil then
          tmpItems[widget:getItemId()] = 1
          newConfig = newConfig .. "\n" .. widget:getItemId()
        end
      end
      if widget == focusedWidget then
        focusIndex = i
      end
    end
    for i, widget in ipairs(lootContainers) do
      if widget:getItemId() >= 100 then
        if tmpContainers[widget:getItemId()] == nil then
          tmpContainers[widget:getItemId()] = 1 -- remove duplicates
          newConfig = newConfig .. "\ncontainer:" .. widget:getItemId()
        end
      end
    end

    context.storage.looting.configs[context.storage.looting.activeConfig] = newConfig
    refreshConfig(focusIndex)
  end

  local parseConfig = function(config)
    items = {}
    itemsByKey = {}
    containers = {}
    commands = {}
    local matches = regexMatch(config, [[([^:^\n^\s]+)(:?)([^\n]*)]])
    for i=1,#matches do
      local command = matches[i][2]
      local validation = (matches[i][3] == ":")
      local text = matches[i][4]
      local commandAsNumber = tonumber(command)
      local textAsNumber = tonumber(text)
      if commandAsNumber and commandAsNumber >= 100 then
        table.insert(items, commandAsNumber)
        itemsByKey[commandAsNumber] = 1
      elseif command == "container" and validation and textAsNumber and textAsNumber >= 100 then
        containers[textAsNumber] = 1
      elseif validation then
        table.insert(commands, command .. ":" .. text)
      end
    end

    local itemsToShow = #items + 2
    if itemsToShow % 5 ~= 0 then
      itemsToShow = itemsToShow + 5 - itemsToShow % 5
    end
    if itemsToShow < 10 then
      itemsToShow = 10
    end

    for i=1,itemsToShow do
      local widget = g_ui.createWidget("BotItem", ui.items)
      local itemId = 0
      if i <= #items then
        itemId = items[i]
      end
      widget:setItemId(itemId)
      widget.onItemChange = createNewConfig
    end

    for i, widget in ipairs(lootContainers) do
        widget:setItemId(0)
    end
    local containerIndex = 1
    for containerId, i in pairs(containers) do
      if lootContainers[containerIndex] then
        lootContainers[containerIndex]:setItemId(containerId)
      end
      containerIndex = containerIndex + 1
    end
    for i, widget in ipairs(lootContainers) do
      widget.onItemChange = createNewConfig
    end
  end

  local ignoreOnOptionChange = true
  refreshConfig = function(focusIndex)
    ignoreOnOptionChange = true
    if context.storage.looting.enabled then
      ui.enableButton:setText("On")
      ui.enableButton:setColor('#00AA00FF')
    else
      ui.enableButton:setText("Off")
      ui.enableButton:setColor('#FF0000FF')
    end

    ui.config:clear()
    for i, config in ipairs(context.storage.looting.configs) do
      local name = getConfigName(config)
      if not name then
        name = "Unnamed config"
      end
      ui.config:addOption(name)
    end

    if (not context.storage.looting.activeConfig or context.storage.looting.activeConfig == 0) and #context.storage.looting.configs > 0 then
       context.storage.looting.activeConfig = 1
    end

    ui.items:destroyChildren()
    for i, widget in ipairs(lootContainers) do
      widget.onItemChange = nil
      widget:setItemId(0)
      widget:setItemCount(0)
    end

    if context.storage.looting.activeConfig and context.storage.looting.configs[context.storage.looting.activeConfig] then
      ui.config:setCurrentIndex(context.storage.looting.activeConfig)
      parseConfig(context.storage.looting.configs[context.storage.looting.activeConfig])
    end

    context.saveConfig()
    if focusIndex and focusIndex > 0 and ui.items:getChildByIndex(focusIndex) then
      ui.items:focusChild(ui.items:getChildByIndex(focusIndex))
    end

    ignoreOnOptionChange = false
  end

  ui.config.onOptionChange = function(widget)
    if not ignoreOnOptionChange then
      context.storage.looting.activeConfig = widget.currentIndex
      refreshConfig()
    end
  end
  ui.enableButton.onClick = function()
    if not context.storage.looting.activeConfig or not context.storage.looting.configs[context.storage.looting.activeConfig] then
      return
    end
    context.storage.looting.enabled = not context.storage.looting.enabled
    refreshConfig()
  end
  ui.add.onClick = function()
    modules.client_textedit.multilineEditor("Looting editor", "name:Config name", function(newText)
      table.insert(context.storage.looting.configs, newText)
      context.storage.looting.activeConfig = #context.storage.looting.configs
      refreshConfig()
    end)
  end
  ui.edit.onClick = function()
    if not context.storage.looting.activeConfig or not context.storage.looting.configs[context.storage.looting.activeConfig] then
      return
    end
    modules.client_textedit.multilineEditor("Looting editor", context.storage.looting.configs[context.storage.looting.activeConfig], function(newText)
      context.storage.looting.configs[context.storage.looting.activeConfig] = newText
      refreshConfig()
    end)
  end
  ui.remove.onClick = function()
    if not context.storage.looting.activeConfig or not context.storage.looting.configs[context.storage.looting.activeConfig] then
      return
    end
    local questionWindow = nil
    local closeWindow = function()
      questionWindow:destroy()
    end
    local removeConfig = function()
      closeWindow()
      if not context.storage.looting.activeConfig or not context.storage.looting.configs[context.storage.looting.activeConfig] then
        return
      end
      context.storage.looting.enabled = false
      table.remove(context.storage.looting.configs, context.storage.looting.activeConfig)
      context.storage.looting.activeConfig = 0
      refreshConfig()
    end
    questionWindow = context.displayGeneralBox(tr('Remove config'), tr('Do you want to remove current looting config?'), {
      { text=tr('Yes'), callback=removeConfig },
      { text=tr('No'), callback=closeWindow },
      anchor=AnchorHorizontalCenter}, removeConfig, closeWindow)
  end
  refreshConfig()

  context.onContainerOpen(function(container, prevContainer)
    if context.storage.attacking.enabled then
      return
    end
    if prevContainer then
      container.autoLooting = prevContainer.autoLooting
    else
      container.autoLooting = true
    end
  end)

  context.macro(200, function()
    if not context.storage.looting.enabled then
      return
    end
    local candidates = {}
    local lootContainersCandidates = {}
    for containerId, container in pairs(g_game.getContainers()) do
      local containerItem = container:getContainerItem()
      if container.autoLooting and container:getItemsCount() > 0 and (not containerItem or containers[containerItem:getId()] == nil) then
        table.insert(candidates, container)
      elseif containerItem and containers[containerItem:getId()] ~= nil then
        table.insert(lootContainersCandidates, container)
      end
    end
    if #lootContainersCandidates == 0 then
      for slot = InventorySlotFirst, InventorySlotLast do
        local item = context.getInventoryItem(slot)
        if item and item:isContainer() and containers[item:getId()] ~= nil then
          table.insert(lootContainersCandidates, item)
        end
      end
      if #lootContainersCandidates > 0 then
        -- try to open inventory backpack
        local target = lootContainersCandidates[math.random(1,#lootContainersCandidates)]
        g_game.open(target, nil)
        context.delay(200)
      end
      return
    end

    if #candidates == 0 then
      return
    end

    local container = candidates[math.random(1,#candidates)]
    local nextContainers = {}
    local foundItem = nil
    for i, item in ipairs(container:getItems()) do
      if item:isContainer() then
        table.insert(nextContainers, item)
      elseif itemsByKey[item:getId()] ~= nil then
        foundItem = item
        break
      end
    end

    -- found item to loot
    if foundItem then
      -- find backpack for it, first backpack with same items
      for i, container in ipairs(lootContainersCandidates) do
        if container:getItemsCount() < container:getCapacity() or foundItem:isStackable() then -- has space
          for j, item in ipairs(container:getItems()) do
            if item:getId() == foundItem:getId() then
              if foundItem:isStackable() then
                if item:getCount() ~= 100  then
                  g_game.move(foundItem, container:getSlotPosition(j - 1), foundItem:getCount())
                  return
                end
              else
                g_game.move(foundItem, container:getSlotPosition(container:getItemsCount()), foundItem:getCount())
                return
              end
            end
          end
        end
      end
      -- now any backpack with empty slot
      for i, container in ipairs(lootContainersCandidates) do
        if container:getItemsCount() < container:getCapacity() then -- has space
          g_game.move(foundItem, container:getSlotPosition(container:getItemsCount()), foundItem:getCount())
          return
        end
      end

      -- can't find backpack, try to open new
      for i, container in ipairs(lootContainersCandidates) do
        local candidates = {}
        for j, item in ipairs(container:getItems()) do
          if item:isContainer() and containers[item:getId()] ~= nil then
            table.insert(candidates, item)
          end
        end
        if #candidates > 0 then
          g_game.open(candidates[math.random(1,#candidates)], container)
          return
        end
        -- full, close it
        g_game.close(container)
        return
      end
      return
    end

    -- open remaining containers
    if #nextContainers == 0 then
      return
    end
    local delay = 1
    for i=2,#nextContainers do
      -- if more than 1 container, open them in new window
      context.schedule(delay, function()
        g_game.open(nextContainers[i], nil)
      end)
      delay = delay + 250
    end
    context.schedule(delay, function()
      g_game.open(nextContainers[1], container)
    end)
    context.delay(150 + delay)
  end)
end
