local _, ns = ...

ns.Tracking = {}
local Tracking = ns.Tracking

local function ensureZoneEntry(zoneName)
    zoneName = zoneName or "Unknown Zone"
    ns.DB.v2.zoneStats[zoneName] = ns.DB.v2.zoneStats[zoneName] or {}
    local entry = ns.DB.v2.zoneStats[zoneName]
    entry.catches = entry.catches or 0
    entry.casts = entry.casts or 0
    entry.rares = entry.rares or 0
    entry.lastCatch = entry.lastCatch or "None"
    entry.items = entry.items or {}
    entry.qualityBreakdown = entry.qualityBreakdown or { common = 0, uncommon = 0, rare = 0 }
    return entry
end

local function pushFront(list, value, limit)
    list = list or {}
    table.insert(list, 1, value)
    while #list > (limit or 5) do
        table.remove(list)
    end
    return list
end

local function shouldSkipDuplicateCatch(key)
    local normalized = ns.Utils and ns.Utils.CleanDisplayText and ns.Utils:CleanDisplayText(key) or tostring(key or "")
    normalized = string.lower(normalized or "")
    ns.state.lastCatchKey = ns.state.lastCatchKey or ""
    ns.state.lastCatchAt = ns.state.lastCatchAt or 0
    local now = GetTime and GetTime() or 0
    if normalized ~= "" and normalized == ns.state.lastCatchKey and (now - ns.state.lastCatchAt) < 2.0 then
        return true
    end
    ns.state.lastCatchKey = normalized
    ns.state.lastCatchAt = now
    return false
end

function Tracking:RefreshAll()
    if not ns.DB then return end
    ns.DB.currentSession.zone = ns.Utils:GetZoneName()
    ns.DB.currentSession.fishingSkill = ns.Utils:GetFishingSkill()
    if ns.UI then ns.UI:RefreshAll() end
end

function Tracking:RecordCast()
    if ns.DB.profile.tracking.autoStartSession then ns.Session:EnsureSession() end
    local session = ns.DB.currentSession
    session.zone = ns.Utils:GetZoneName()
    session.casts = (session.casts or 0) + 1
    ns.DB.stats.totalCasts = (ns.DB.stats.totalCasts or 0) + 1
    local zoneName = ns.Utils:GetZoneName()
    local zoneEntry = ensureZoneEntry(zoneName)
    zoneEntry.casts = zoneEntry.casts + 1
    if ns.UI then ns.UI:RefreshAll() end
end

function Tracking:RecordCatch(itemLink)
    if not itemLink or itemLink == "" then return false end
    if shouldSkipDuplicateCatch(itemLink) then return false end

    if ns.DB.profile.tracking.autoStartSession then ns.Session:EnsureSession() end
    local session = ns.DB.currentSession
    local key = itemLink or "Unknown Catch"
    local displayName = (ns.Utils and ns.Utils.CleanDisplayText and ns.Utils:CleanDisplayText(key)) or tostring(key)
    local zoneName = ns.Utils:GetZoneName()
    local zoneEntry = ensureZoneEntry(zoneName)

    session.zone = zoneName
    session.catches = (session.catches or 0) + 1
    session.lastCatch = displayName
    session.items = session.items or {}
    session.items[key] = (session.items[key] or 0) + 1
    session.recentCatches = pushFront(session.recentCatches or {}, displayName, 6)
    ns.DB.stats.totalCatches = (ns.DB.stats.totalCatches or 0) + 1
    ns.DB.stats.totalFishLoots = (ns.DB.stats.totalFishLoots or 0) + 1

    zoneEntry.catches = zoneEntry.catches + 1
    zoneEntry.lastCatch = displayName
    zoneEntry.items[key] = (zoneEntry.items[key] or 0) + 1
    ns.DB.v2.itemStats[key] = (ns.DB.v2.itemStats[key] or 0) + 1

    -- Pool vs open water
    if ns.state.lastCastIsPool then
        session.poolCatches = (session.poolCatches or 0) + 1
    else
        session.openWaterCatches = (session.openWaterCatches or 0) + 1
    end

    -- Quality breakdown per zone
    local quality = ns.Utils:GetItemQuality(itemLink)
    zoneEntry.qualityBreakdown = zoneEntry.qualityBreakdown or { common = 0, uncommon = 0, rare = 0 }
    if quality >= 3 then
        zoneEntry.qualityBreakdown.rare = (zoneEntry.qualityBreakdown.rare or 0) + 1
    elseif quality >= 2 then
        zoneEntry.qualityBreakdown.uncommon = (zoneEntry.qualityBreakdown.uncommon or 0) + 1
    else
        zoneEntry.qualityBreakdown.common = (zoneEntry.qualityBreakdown.common or 0) + 1
    end

    -- Milestone alerts
    if ns.DB.profile.alerts.milestoneAlerts then
        local total = ns.DB.stats.totalCatches
        for _, milestone in ipairs({ 100, 250, 500, 1000, 2500, 5000, 10000 }) do
            if total == milestone then
                ns.Utils:Print(string.format("|cFFFFD700Milestone: %d total catches reached! Still reeling...|r", milestone))
                break
            end
        end
    end

    if ns.Utils:IsRareQuality(itemLink) then
        session.rareCatches = (session.rareCatches or 0) + 1
        session.recentRares = pushFront(session.recentRares or {}, displayName, 5)
        zoneEntry.rares = zoneEntry.rares + 1
        ns.DB.v2.rareItems[itemLink] = time()
        ns.DB.v2.recentRares = pushFront(ns.DB.v2.recentRares or {}, {
            itemLink = itemLink,
            displayName = displayName,
            zone = zoneName,
            at = time(),
        }, 12)
        ns.Alerts:PlayRareAlert(itemLink)
    end
    if ns.UI then ns.UI:RefreshAll() end
    return true
end

function Tracking:GetCatchRate()
    -- Prevent inflated pace in very short sessions by using a 5-minute minimum sample window.
    return ns.Utils:FormatPerHour(ns.DB.currentSession.catches or 0, ns.Session:GetElapsed(), 300)
end

function Tracking:GetCastRate()
    return ns.Utils:FormatPerHour(ns.DB.currentSession.casts or 0, ns.Session:GetElapsed())
end

function Tracking:GetZoneStats(zoneName)
    return ensureZoneEntry(zoneName or ns.Utils:GetZoneName())
end

function Tracking:GetZoneTopItems(zoneName, limit)
    local entry = ensureZoneEntry(zoneName or ns.Utils:GetZoneName())
    return ns.Utils:BuildTopList(entry.items, limit or 6)
end

function Tracking:GetSessionTopItems(limit)
    return ns.Utils:BuildTopList(ns.DB.currentSession.items or {}, limit or 6)
end

function Tracking:GetHotspotZones(limit)
    local rows = {}
    for zoneName, info in pairs(ns.DB.v2.zoneStats or {}) do
        table.insert(rows, {
            zone = zoneName,
            catches = tonumber(info.catches) or 0,
            casts = tonumber(info.casts) or 0,
            rares = tonumber(info.rares) or 0,
            lastCatch = info.lastCatch or "None",
        })
    end
    table.sort(rows, function(a, b)
        if a.catches == b.catches then
            if a.casts == b.casts then
                return a.zone < b.zone
            end
            return a.casts > b.casts
        end
        return a.catches > b.catches
    end)
    if limit and #rows > limit then
        while #rows > limit do
            table.remove(rows)
        end
    end
    return rows
end

function Tracking:GetRecentRares(limit)
    local rows = {}
    for _, entry in ipairs(ns.DB.v2.recentRares or {}) do
        table.insert(rows, entry)
    end
    if limit and #rows > limit then
        while #rows > limit do
            table.remove(rows)
        end
    end
    return rows
end

function Tracking:GetZoneQualityBreakdown(zoneName)
    local entry = ensureZoneEntry(zoneName or ns.Utils:GetZoneName())
    local qb = entry.qualityBreakdown or { common = 0, uncommon = 0, rare = 0 }
    return qb.common or 0, qb.uncommon or 0, qb.rare or 0
end
