local DEFAULT_FOOD_IDS = {
	3595, -- carrot
	3577, -- meat
	3578, -- fish
	3579, -- salmon
	3580, -- northern pike
	3581, -- shrimp
	3582, -- ham
	3583, -- dragon ham
	3584, -- pear
	3585, -- red apple
	3586, -- orange
	3587, -- banana
	3588, -- blueberry
	3589, -- coconut
	3590, -- cherry
	3591, -- strawberry
	3592, -- grapes
	3593, -- melon
	3594, -- pumpkin
	3596, -- tomato
	3597, -- corncob
	130, -- cookie
	3599, -- candy cane
	3600, -- bread
	3601, -- roll
	3602, -- brown bread
	3606, -- egg
	169, -- cheese
	3723, -- white mushroom
	3724, -- red mushroom
	3725, -- brown mushroom
	3726, -- orange mushroom
	3727, -- wood mushroom
	3728, -- dark mushroom
	3730, -- some mushrooms
	3731, -- fire mushroom
	3732, -- green mushroom
	5096, -- mango
	5678, -- tortoise egg
	6125, -- tortoise egg from Nargor
	6277, -- cake
	6278, -- decorated cake
	6392, -- valentine's cake
	904, -- cream cake
	6500, -- gingerbread man
	6541, -- coloured egg (yellow)
	6542, -- coloured egg (red)
	6543, -- coloured egg (blue)
	6544, -- coloured egg (green)
	6545, -- coloured egg (purple)
	6569, -- candy
	6574, -- bar of chocolate
	7158, -- rainbow trout
	7159, -- green perch
	229, -- ice cream cone (crispy chocolate chips)
	7373, -- ice cream cone (velvet vanilla)
	7374, -- ice cream cone (sweet strawberry)
	7375, -- ice cream cone (chilly cherry)
	7376, -- ice cream cone (mellow melon)
	7377, -- ice cream cone (blue-barian)
	836, -- walnut
	841, -- peanut
	901, -- marlin
	3607, -- scarab cheese
	8010, -- potato
	8011, -- plum
	8012, -- raspberry
	8013, -- lemon
	8014, -- cucumber
	8015, -- onion
	8016, -- jalapeño pepper
	8017, -- beetroot
	8019, -- chocolate cake
	8177, -- yummy gummy worm
	8197, -- bulb of garlic
	9083, -- banana chocolate shake
	9537, -- headache pill
	10329, -- rice ball
	10453, -- terramite eggs
	10219, -- crocodile steak
	11459, -- pineapple
	11460, -- aubergine
	11461, -- broccoli
	11462, -- cauliflower
	11681, -- ectoplasmic sushi
	11682, -- dragonfruit
	11683 -- peas
}

local trainWindow
local trainButton
local enableButton
local enableCheck
local eatCheck
local spellSlot
local manaSpin
local spellCheckEvent

local settingsKey = 'trainSettings'
local settings = {
  enabled = false,
  autoEat = false,
  spellWords = '',
  spellName = '',
  manaPercent = 90,
}

local foodIdSet = {}
local foodIdList = {}
local eatEvent
local updatingUI = false
local manaAboveThreshold = false
local lastSpellTime = 0

local EAT_INTERVAL_WITH_FOOD = 60 * 1000
local EAT_INTERVAL_NO_FOOD = 15 * 1000
local SPELL_COOLDOWN = 2000
local SPELL_CHECK_INTERVAL = 2000

local function saveSettings()
  g_settings.setNode(settingsKey, settings)
end

local function buildFoodLists()
  foodIdSet = {}
  foodIdList = {}

  for _, id in ipairs(DEFAULT_FOOD_IDS) do
    if not foodIdSet[id] then
      foodIdSet[id] = true
      table.insert(foodIdList, id)
    end
  end
end

local function findFoodItem()
  for _, id in ipairs(foodIdList) do
    local item = g_game.findItemInContainers(id, -1)
    if item then
      return item
    end
  end
end

local function shouldAutoEat()
  return settings.enabled and settings.autoEat and g_game.isOnline()
end

local function stopEatEvent()
  if eatEvent then
    removeEvent(eatEvent)
    eatEvent = nil
  end
end

local function scheduleEat(delay)
  stopEatEvent()
  eatEvent = scheduleEvent(function()
    eatEvent = nil
    if not shouldAutoEat() then
      return
    end

    local foodItem = findFoodItem()
    if foodItem then
      g_game.use(foodItem)
      scheduleEat(EAT_INTERVAL_WITH_FOOD)
    else
      scheduleEat(EAT_INTERVAL_NO_FOOD)
    end
  end, delay or 0)
end

local function refreshEatLoop()
  if shouldAutoEat() then
    scheduleEat(0)
  else
    stopEatEvent()
  end
end

local function stopSpellEvent()
  if spellCheckEvent then
    spellCheckEvent:cancel()
    spellCheckEvent = nil
  end
end

local function evaluateSpellCasting(localPlayer)
  if not settings.enabled or settings.spellWords == '' or not g_game.isOnline() then
    manaAboveThreshold = false
    return
  end

  local player = localPlayer or g_game.getLocalPlayer()
  if not player then
    manaAboveThreshold = false
    return
  end

  local mana = player.getMana and player:getMana() or nil
  local maxMana = player.getMaxMana and player:getMaxMana() or nil
  if not mana or not maxMana or maxMana <= 0 then
    manaAboveThreshold = false
    return
  end

  local threshold = math.max(0, math.min(100, settings.manaPercent or 0))
  local requiredMana = threshold <= 0 and 0 or math.ceil((threshold / 100) * maxMana)

  if mana >= requiredMana then
    local now = g_clock.millis()
    if (not manaAboveThreshold) or (now - lastSpellTime > SPELL_COOLDOWN) then
      g_game.talk(settings.spellWords)
      lastSpellTime = now
    end
    manaAboveThreshold = true
  else
    manaAboveThreshold = false
  end
end

local function refreshSpellLoop()
  if not (settings.enabled and settings.spellWords ~= '' and g_game.isOnline()) then
    stopSpellEvent()
    return
  end

  if not spellCheckEvent then
    spellCheckEvent = cycleEvent(function()
      evaluateSpellCasting()
    end, SPELL_CHECK_INTERVAL)
  end

  evaluateSpellCasting()
end

local function updateSpellSlotDisplay()
  if not spellSlot then return end

  if settings.spellName and settings.spellName ~= '' then
    local profile = Spells.getSpellProfileByName(settings.spellName)
    local iconId = tonumber(Spells.getClientId(settings.spellName))
    if profile and iconId then
      spellSlot:setImageSource(SpelllistSettings[profile].iconFile)
      spellSlot:setImageClip(Spells.getImageClip(iconId, profile))
    end
    spellSlot:getChildById('spellName'):setText(settings.spellName)
  else
    spellSlot:setImageSource('')
    spellSlot:setImageClip('0 0 0 0')
    spellSlot:getChildById('spellName'):setText('Select spell...')
  end
end

local function updateUI()
  if updatingUI then
    return
  end

  updatingUI = true
  if enableButton then
    enableButton:setOn(settings.enabled)
  elseif enableCheck then
    enableCheck:setChecked(settings.enabled)
  end
  if eatCheck then
    eatCheck:setChecked(settings.autoEat)
  end
  updateSpellSlotDisplay()
  if manaSpin then
    manaSpin:setValue(settings.manaPercent or 0, true)
  end
  updatingUI = false
end

local function onSpellSelected(spellInfo)
  if updatingUI then return end
  local words = spellInfo.words or ''
  if spellInfo.parameter and spellInfo.parameter ~= '' then
    words = words .. ' "' .. spellInfo.parameter .. '"'
  end
  settings.spellWords = words
  settings.spellName = spellInfo.name or ''
  saveSettings()
  updateUI()
  refreshSpellLoop()
end

local function onManaPercentChange(value)
  if updatingUI then return end
  settings.manaPercent = math.max(0, math.min(100, value))
  saveSettings()
  refreshSpellLoop()
end

local function setBotEnabled(enabled)
  enabled = enabled and true or false
  if settings.enabled == enabled then
    return
  end

  settings.enabled = enabled
  saveSettings()
  manaAboveThreshold = false
  refreshEatLoop()
  refreshSpellLoop()
  updateUI()
end

local function onManaChanged(localPlayer, mana, maxMana)
  evaluateSpellCasting(localPlayer)
end

local function setupMiniWindowButtons()
  for _, id in ipairs({ 'toggleFilterButton', 'contextMenuButton', 'newWindowButton' }) do
    local button = trainWindow:recursiveGetChildById(id)
    if button then
      button:setVisible(false)
    end
  end

  local lockButton = trainWindow:recursiveGetChildById('lockButton')
  local minimizeButton = trainWindow:recursiveGetChildById('minimizeButton')
  if lockButton and minimizeButton then
    lockButton:breakAnchors()
    lockButton:addAnchor(AnchorTop, minimizeButton:getId(), AnchorTop)
    lockButton:addAnchor(AnchorRight, minimizeButton:getId(), AnchorLeft)
    lockButton:setMarginRight(7)
    lockButton:setMarginTop(0)
  end

end

local function toggle()
  if trainButton:isOn() then
    trainButton:setOn(false)
    trainWindow:hide()
  else
    trainButton:setOn(true)
    trainWindow:show()
    trainWindow:raise()
  end
end

local function onGameStart()
  setBotEnabled(false)
  manaAboveThreshold = false
  refreshEatLoop()
  refreshSpellLoop()
end

local function onGameEnd()
  stopEatEvent()
  manaAboveThreshold = false
  stopSpellEvent()
end

function init()
  g_logger.info('[Train] init module')

  connect(g_game, {
    onGameStart = onGameStart,
    onGameEnd = onGameEnd
  })

  connect(LocalPlayer, {
    onManaChange = onManaChanged
  })

  buildFoodLists()

  local stored = g_settings.getNode(settingsKey)
  if type(stored) == 'table' then
    settings.enabled = not not stored.enabled
    settings.autoEat = not not stored.autoEat
    settings.spellWords = stored.spellWords or ''
    settings.spellName = stored.spellName or ''
    settings.manaPercent = stored.manaPercent or settings.manaPercent
  end

  if settings.enabled then
    settings.enabled = false
    saveSettings()
  end

  trainButton = modules.game_mainpanel.addToggleButton('trainButton', tr('Train'), '/images/options/bot', toggle, false, 5)
  trainButton:setOn(false)

  trainWindow = g_ui.loadUI('train', modules.game_interface.getRightPanel())
  trainWindow:setup()
  trainWindow:setVisible(false)
  trainWindow:setContentMinimumHeight(150)

  setupMiniWindowButtons()

  local contents = trainWindow:recursiveGetChildById('contentsPanel')
  enableCheck = contents:getChildById('enableTrainCheck')
  enableButton = contents:getChildById('enableTrainButton') or enableCheck
  eatCheck = contents:getChildById('eatFoodCheck')
  spellSlot = contents:recursiveGetChildById('spellSlot')
  manaSpin = contents:recursiveGetChildById('manaPercentSpinBox')

  updatingUI = true
  if enableButton then
    enableButton:setOn(settings.enabled)
  end
  eatCheck:setChecked(settings.autoEat)
  updateSpellSlotDisplay()
  manaSpin:setValue(settings.manaPercent or 0, true)
  updatingUI = false

  if enableButton then
    enableButton.onClick = function()
      if updatingUI then return end
      setBotEnabled(not settings.enabled)
    end
  elseif enableCheck then
    enableCheck.onCheckChange = function(_, checked)
      if updatingUI then return end
      setBotEnabled(checked)
    end
  end

  eatCheck.onCheckChange = function(_, checked)
    if updatingUI then return end
    settings.autoEat = checked
    saveSettings()
    refreshEatLoop()
  end

  spellSlot.onMousePress = function()
    modules.game_actionbar.openSpellAssignWindow(onSpellSelected)
    return true
  end

  manaSpin.onValueChange = function(_, value)
    onManaPercentChange(value)
  end

  refreshEatLoop()
  refreshSpellLoop()
end

function terminate()
  stopEatEvent()
  stopSpellEvent()
  disconnect(LocalPlayer, {
    onManaChange = onManaChanged
  })
  disconnect(g_game, {
    onGameStart = onGameStart,
    onGameEnd = onGameEnd
  })

  if trainWindow then
    trainWindow:destroy()
    trainWindow = nil
  end
  if trainButton then
    trainButton:destroy()
    trainButton = nil
  end

  enableButton = nil
  enableCheck = nil
  eatCheck = nil
  spellSlot = nil
  manaSpin = nil
  spellCheckEvent = nil
end

function onMiniWindowClose()
  if trainButton then
    trainButton:setOn(false)
  end
end
