-- Weekly tasks tab logic — methods added to TaskBoardController
--  Server data handler 
local function getItemServerName(itemId)
    local thingType = g_things.getThingType(itemId, ThingCategoryItem)
    if thingType then
        return thingType:getName()
    end
    return "Unknown Item"
end

local function countFinishedEntries(entries)
    local total = 0
    for _, entry in ipairs(entries or {}) do
        if entry.finished then
            total = total + 1
        end
    end
    return total
end

function TaskBoardController:refreshWeeklySummary()
    local header = self.weeklyHdr or {}
    local completedKillTasks = tonumber(header.completedKillTasks)
    if completedKillTasks == nil then
        completedKillTasks = countFinishedEntries(self.weeklyMonsters)
    end
    local completedDeliveryTasks = tonumber(header.completedDeliveryTasks) or 0
    local totalTaskSlots = tonumber(header.totalTaskSlots) or WEEKLY_DEFAULT_TASK_SLOTS
    local maxExperience = tonumber(header.maxExperience) or 0
    local maxDeliveryExperience = tonumber(header.maxDeliveryExperience) or 0
    local difficultyId = tonumber(header.difficulty) or 0
    local killTaskPoints = WEEKLY_KILL_TASK_POINTS[difficultyId] or WEEKLY_KILL_TASK_POINTS[1]
    local deliveryTaskPoints = WEEKLY_DELIVERY_TASK_POINTS
    local soulsealPointsPerTask = WEEKLY_SOULSEAL_POINTS_PER_TASK
    local totalCompleted = completedKillTasks + completedDeliveryTasks
    local pointsEarned = tonumber(header.pointsEarned) or 0
    local soulsealsEarned = tonumber(header.soulsealsEarned) or 0
    local killBase = completedKillTasks * killTaskPoints
    local deliveryBase = completedDeliveryTasks * deliveryTaskPoints
    local basePoints = killBase + deliveryBase
    local rewardMultiplier = (basePoints > 0) and math.max(1, math.floor(pointsEarned / basePoints + 0.5)) or 1

    self.weeklyHdr.completedKillTasks = completedKillTasks

    self.weeklyRewardTokens = comma_value(pointsEarned)
    self.weeklyRewardSeals = comma_value(soulsealsEarned)
    self.weeklyRemainingDays = tonumber(header.remainingDays) or 0
    self.weeklyShowExtraSlotUnlock = not ((tonumber(header.extraSlot) or 0) == 1 or header.extraSlot == true)
    self.weeklyProgressPct = self:calcProgressWidth(totalCompleted)
    self.weeklyXpText = (maxExperience > 0) and
                            tr(
            'Each kill task rewards you with %s XP and each delivery task will reward you with %s XP.',
            comma_value(maxExperience), comma_value(maxDeliveryExperience)) or ""

    self.weeklyProgressTooltip = string.format('Kill Tasks: %d\nDelivery Tasks: %d\nTotal: %d', completedKillTasks,
        completedDeliveryTasks, totalCompleted)

    self.weeklyRewardTokensTooltip = string.format(
        'Hunting Task Points:\n\n   %d * %d  (Kill Tasks)\n+ %d * %d  (Delivery Tasks)\n--------------------------------------\n= %s  base points\nx %d  reward multiplier\n= %s  Hunting Task Points',
        completedKillTasks, killTaskPoints, completedDeliveryTasks, deliveryTaskPoints,
        comma_value(killBase + deliveryBase), rewardMultiplier, comma_value(pointsEarned))

    self.weeklyRewardSealsTooltip = string.format(
        'You receive %d Soulseal for each completed task. Soulseals can be\nused in the Soulpit. Click the obelisk there, then your character to\nopen a menu where you can select a creature you want to\nchallenge on your own.',
        soulsealPointsPerTask)

    self.weeklyDifficultySummaryVisible = completedKillTasks > 0 or completedDeliveryTasks > 0
    self.weeklyDifficultyKillSummary = string.format('You have completed %d / %d kill tasks.', completedKillTasks,
        totalTaskSlots)
    self.weeklyDifficultyDeliverySummary = string.format('You have completed %d / %d delivery tasks.',
        completedDeliveryTasks, totalTaskSlots)
    self.weeklyDifficultyPointsEarned = comma_value(pointsEarned)
    self.weeklyDifficultySealsEarned = comma_value(soulsealsEarned)
end

function TaskBoardController:onWeeklyServerData(header, monsters, items)
    if type(header) ~= 'table' then
        return
    end
    monsters = type(monsters) == 'table' and monsters or {}
    items = type(items) == 'table' and items or {}

    -- Update tracker regardless of UI state
    if Tracker and Tracker.Weekly then
        Tracker.Weekly.loadFromServerData(monsters)
    end

    local playerLevel = tonumber(header.currentPlayerLevel) or
                            (g_game.getLocalPlayer() and g_game.getLocalPlayer():getLevel() or 0)
    local data = {
        difficulty = tonumber(header.difficulty) or 0,
        remainingDays = tonumber(header.remainingDays) or 7,
        totalTaskSlots = tonumber(header.totalTaskSlots) or WEEKLY_DEFAULT_TASK_SLOTS,
        maxExperience = tonumber(header.maxExperience) or 0,
        maxDeliveryExperience = tonumber(header.maxDeliveryExperience) or 0,
        completedKillTasks = tonumber(header.completedKillTasks) or 0,
        completedDeliveryTasks = tonumber(header.completedDeliveryTasks) or 0,
        pointsEarned = tonumber(header.pointsEarned) or 0,
        soulsealsEarned = tonumber(header.soulsealsEarned) or 0,
        extraSlot = (tonumber(header.extraSlot) or 0) == 1,
        weeklyProgressFinished = (tonumber(header.weeklyProgressFinished) or 0) == 1
    }

    -- Build weeklyMonsters list
    local monsterList = {}
    for _, m in ipairs(monsters) do
        m = type(m) == 'table' and m or {}
        local raceId = tonumber(m.raceId) or 0
        local raceData = raceId > 0 and g_things.getRaceData(raceId) or nil
        local fullName = raceId == 0 and 'Any Creature' or ((raceData and raceData.name) or 'Unknown')
        if raceId > 0 then
            fullName = fullName:capitalize()
        end
        local shortName = fullName
        if #shortName > 20 then
            shortName = shortName:sub(1, 17) .. '...'
        end
        local finished = (tonumber(m.state) or 0) == 1
        table.insert(monsterList, {
            raceId = raceId,
            name = shortName,
            fullName = fullName,
            outfit = raceData and raceData.outfit or nil,
            current = tonumber(m.current) or 0,
            total = tonumber(m.total) or 0,
            finished = finished,
            showProgress = not finished,
            anyCreature = raceId == 0
        })
    end
    self.weeklyMonsters = monsterList

    -- Build weeklyItems list
    local itemList = {}
    for i, it in ipairs(items) do
        it = type(it) == 'table' and it or {}
        local itemId = tonumber(it.itemId) or 0
        local itemName = itemId > 0 and (getItemServerName(itemId) or tostring(itemId)) or "Unknown Item"
        local current = tonumber(it.current) or 0
        local total = tonumber(it.total) or 0
        local delivered = (tonumber(it.claimed) or 0) == 1
        local finished = (tonumber(it.state) or 0) == 1
        local canDeliver = finished and not delivered
        table.insert(itemList, {
            itemId = itemId,
            itemName = itemName,
            current = current,
            total = total,
            delivered = delivered,
            finished = finished,
            slotIndex = tonumber(it.slotIndex) or (i - 1),
            canDeliver = canDeliver,
            showProgress = not delivered
        })
    end
    self.weeklyItems = itemList

    -- Build difficulties list for modal (from client-side constant — server does not send it)
    local diffList = {}
    for _, d in ipairs(WEEKLY_DIFFICULTIES) do
        local canSelect = playerLevel >= d.minLevel
        table.insert(diffList, {
            id = d.id,
            name = d.name,
            minLevel = d.minLevel,
            canSelect = canSelect,
            tooltip = (not canSelect) and string.format('The minimum level to start this difficulty is %d', d.minLevel) or
                nil
        })
    end
    self.weeklyDifficulties = diffList

    self.weeklyHdr = data
    self:refreshWeeklySummary()

    -- Difficulty modal
    self.weeklyDifficultyPending = data.difficulty == 0 or data.weeklyProgressFinished
    self.diffModalVisible = false

    self:onWeeklyTabSelected()
end

--  Kill update 

function TaskBoardController:onWeeklyKillUpdate(raceId, currentKills, totalKills, isCompleted)
    if Tracker and Tracker.Weekly then
        Tracker.Weekly.onKillUpdate(raceId, currentKills, totalKills, isCompleted)
    end
    if type(self.weeklyMonsters) ~= "table" then
        self.weeklyMonsters = {}
        return
    end

    -- Update matching entry in weeklyMonsters
    local completionChanged = false
    for i, m in ipairs(self.weeklyMonsters) do
        if m.raceId == raceId then
            completionChanged = m.finished ~= (isCompleted == 1)
            self.weeklyMonsters[i].current = currentKills
            self.weeklyMonsters[i].total = totalKills
            self.weeklyMonsters[i].finished = isCompleted == 1
            self.weeklyMonsters[i].showProgress = isCompleted ~= 1
            self.weeklyMonsters = self.weeklyMonsters
            break
        elseif raceId == 0 and m.anyCreature then
            completionChanged = m.finished ~= (isCompleted == 1)
            self.weeklyMonsters[i].current = currentKills
            self.weeklyMonsters[i].total = totalKills
            self.weeklyMonsters[i].finished = isCompleted == 1
            self.weeklyMonsters[i].showProgress = isCompleted ~= 1
            self.weeklyMonsters = self.weeklyMonsters
            break
        end
    end

    local completedKillTasks = countFinishedEntries(self.weeklyMonsters)
    self.weeklyHdr.completedKillTasks = completedKillTasks
    self:refreshWeeklySummary()

    if completionChanged and g_game.weeklyTaskAction then
        g_game.weeklyTaskAction(WEEKLY_ACTION_REFRESH_DATA, 0)
    end
end

--  Tab selection 

function TaskBoardController:onWeeklyTabSelected()
    if not self.ui or not self.ui:isVisible() then
        return
    end
    self.diffModalVisible = self.activeTab == self.TAB_WEEKLY and self.weeklyDifficultyPending
end

--  Actions 

function TaskBoardController:selectDifficulty(diffId)
    local parsedId = tonumber(diffId) or 0
    if parsedId <= 0 then
        return
    end
    g_game.weeklyTaskAction(WEEKLY_ACTION_SELECT_DIFFICULTY, parsedId)
    self.weeklyDifficultyPending = false
    self.diffModalVisible = false
    return
end

function TaskBoardController:deliverItem(itemId, slotIndex)
    local parsedItemId = tonumber(itemId) or 0
    local itemName = parsedItemId > 0 and (getItemServerName(parsedItemId) or tostring(parsedItemId)) or "Unknown Item"
    local msgBox
    local function yes()
        if msgBox then
            msgBox:destroy();
            msgBox = nil
        end
        g_game.weeklyTaskAction(WEEKLY_ACTION_DELIVER_ITEM, tonumber(slotIndex) or 0)
    end
    local function no()
        if msgBox then
            msgBox:destroy();
            msgBox = nil
        end
    end
    msgBox = displayGeneralBox(tr('Deliver Item'), tr('Do you want to deliver %s?', itemName), {{
        text = tr('Yes'),
        callback = yes
    }, {
        text = tr('No'),
        callback = no
    }}, yes, no)
end

--  Delivery item right-click context menu

function TaskBoardController:onDeliveryItemsRendered()
    local container = self:findWidget("#deliveryTasksBox")
    if not container then
        return
    end
    local ctrl = self
    for i = 1, container:getChildCount() do
        local card = container:getChildByIndex(i)
        if card and not card:isDestroyed() and card.__for_values then
            local item = card.__for_values[1]
            if item then
                local itemId = tonumber(item.itemId) or 0
                local itemName = tostring(item.itemName or "")
                if itemId > 0 then
                    card.onMouseRelease = function(widget, mousePos, mouseButton)
                        if mouseButton == MouseRightButton then
                            ctrl:showDeliveryItemMenu(itemId, itemName, mousePos)
                            return true
                        end
                    end
                end
            end
        end
    end
end

function TaskBoardController:showDeliveryItemMenu(itemId, itemName, mousePos)
    local menu = g_ui.createWidget('PopupMenu')
    menu:addOption(tr('Cyclopedia'), function()
        local cyc = modules.game_cyclopedia
        if not cyc then
            return
        end
        if controllerCyclopedia and controllerCyclopedia.ui and controllerCyclopedia.ui:isVisible() then
            cyc.SelectWindow('items', false)
        else
            cyc.show('items')
        end
        TaskBoardController:scheduleEvent(function()
            if cyc.Cyclopedia and cyc.Cyclopedia.ItemSearch then
                cyc.Cyclopedia.ItemSearch(itemName, false)
            end
        end, 100, "showDeliveryItemCyclopedia")
    end)
    menu:addOption(tr('Show in Market'), function()
        local market = modules.game_market
        if not market or not market.onShowRedirect then
            return
        end
        local thingType = g_things.getThingType(itemId, ThingCategoryItem)
        if not thingType then
            return
        end
        market.onMarketEnter({}, 0, 0, 0)
        TaskBoardController:scheduleEvent(function()
            market.onShowRedirect(thingType)
        end, 100, "showDeliveryItemMarket")
    end)
    menu:display(mousePos)
end

--  Progress bar helper

function TaskBoardController:calcProgressWidth(completedTasks)
    local sectionIndex = 0
    for i = 1, WEEKLY_SECTIONS do
        if completedTasks >= WEEKLY_THRESHOLDS[i + 1] then
            sectionIndex = i
        else
            break
        end
    end

    local sectionWidth = 100 / WEEKLY_SECTIONS

    if sectionIndex >= WEEKLY_SECTIONS then
        return 100
    end

    local sectionStart = WEEKLY_THRESHOLDS[sectionIndex + 1]
    local sectionEnd = WEEKLY_THRESHOLDS[sectionIndex + 2]
    local fraction = (completedTasks - sectionStart) / (sectionEnd - sectionStart)
    return math.min(math.floor((sectionIndex + fraction) * sectionWidth), 100)
end
