local PT = AhUI
if not PT or not PT.FarmTracker then return end

local FT = PT.FarmTracker
FT.Data = FT.Data or {}
local D = FT.Data
local L = PT.L or {}

local function tcount(tbl)
    local n = 0
    if not tbl then return 0 end
    for _ in pairs(tbl) do
        n = n + 1
    end
    return n
end

local function copyTable(src)
    local out = {}
    if not src then return out end
    for k, v in pairs(src) do
        if type(v) == "table" then
            out[k] = copyTable(v)
        else
            out[k] = v
        end
    end
    return out
end

function D:GetDB()
    AhUI_DB = AhUI_DB or {}
    AhUI_DB.farmTracker = AhUI_DB.farmTracker or {}
    local db = AhUI_DB.farmTracker

    db.config = db.config or {}
    if db.config.enabled == nil then db.config.enabled = false end
    if db.config.autoStartOnLoot == nil then db.config.autoStartOnLoot = false end
    if db.config.resumeUnfinishedSession == nil then db.config.resumeUnfinishedSession = true end
    if db.config.confirmReset == nil then db.config.confirmReset = true end
    if db.config.confirmDelete == nil then db.config.confirmDelete = true end
    if db.config.priceSource == nil then db.config.priceSource = "AUCTIONATOR" end
    if db.config.autoFallback == nil then db.config.autoFallback = true end
    if db.config.includeVendorFallback == nil then db.config.includeVendorFallback = true end
    if db.config.maxHistory == nil then db.config.maxHistory = 100 end
    if db.config.saveDetailedItems == nil then db.config.saveDetailedItems = true end
    if db.config.defaultHistoryFilter == nil then db.config.defaultHistoryFilter = "current" end
    db.config.sources = db.config.sources or {}

    if db.config.sources.mail ~= nil then
        if db.config.sources.mailItems == nil then
            db.config.sources.mailItems = db.config.sources.mail
        end
        if db.config.sources.mailMoney == nil then
            db.config.sources.mailMoney = db.config.sources.mail
        end
        db.config.sources.mail = nil
    end

    if db.config.sources.loot == nil then db.config.sources.loot = true end
    if db.config.sources.crafting == nil then db.config.sources.crafting = true end
    if db.config.sources.money == nil then db.config.sources.money = true end
    if db.config.sources.mailItems == nil then db.config.sources.mailItems = false end
    if db.config.sources.mailMoney == nil then db.config.sources.mailMoney = false end
    db.config.qualityFilter = db.config.qualityFilter or {}
    if db.config.qualityFilter[0] == nil then db.config.qualityFilter[0] = true end
    if db.config.qualityFilter[1] == nil then db.config.qualityFilter[1] = true end
    if db.config.qualityFilter[2] == nil then db.config.qualityFilter[2] = true end
    if db.config.qualityFilter[3] == nil then db.config.qualityFilter[3] = true end
    if db.config.qualityFilter[4] == nil then db.config.qualityFilter[4] = true end
    if db.config.qualityFilter[5] == nil then db.config.qualityFilter[5] = true end
    db.window = db.window or {}
    if db.window.width == nil then db.window.width = 360 end
    if db.window.height == nil then db.window.height = 430 end
    if db.window.collapsedWidth == nil then db.window.collapsedWidth = 360 end
    if db.window.scale == nil then db.window.scale = 1 end

    db.history = db.history or {}
    return db
end

function D:GetCharDB()
    AhUI_CharConfig = AhUI_CharConfig or {}
    AhUI_CharConfig.farmTracker = AhUI_CharConfig.farmTracker or {}
    local db = AhUI_CharConfig.farmTracker

    db.ui = db.ui or {}
    if db.ui.activeTab == nil then db.ui.activeTab = "session" end
    if db.ui.historyFilter == nil then db.ui.historyFilter = "current" end
    if db.ui.sessionSort == nil then db.ui.sessionSort = "value_desc" end
    if db.ui.historySort == nil then db.ui.historySort = "date_desc" end
    if db.ui.detailsSort == nil then db.ui.detailsSort = "value_desc" end
    if db.ui.collapsed == nil then db.ui.collapsed = true end
    return db
end

function D:Init()
    self:GetDB()
    self:GetCharDB()
end

function D:IsEnabled()
    local db = self:GetDB()
    return db.config.enabled == true
end

function D:IsSourceEnabled(kind)
    local db = self:GetDB()
    local src = db.config.sources or {}
    return src[kind] ~= false
end

function D:IsQualityAllowed(quality)
    local db = self:GetDB()
    local qf = db.config.qualityFilter or {}

    quality = tonumber(quality)
    if quality == nil then
        return true
    end

    return qf[quality] ~= false
end

function D:GetActiveSession()
    return self:GetDB().activeSession
end

function D:GetSessionState()
    local s = self:GetActiveSession()
    if not s then return "inactive" end
    return s.state or "inactive"
end

function D:IsSessionActive()
    return self:GetSessionState() == "active"
end

function D:IsSessionPaused()
    return self:GetSessionState() == "paused"
end

function D:GenerateSessionID()
    local t = time()
    local rnd = math.random(1000, 9999)
    return string.format("ft_%d_%d", t, rnd)
end

function D:BuildSessionTitle(session)
    session = session or self:GetActiveSession()
    if not session then return L["FT_NewSession"] or "Session" end
    local dateText = date("%Y-%m-%d", session.startTime or time())
    local zone = session.zone or UNKNOWN
    local name = session.charName or UNKNOWNOBJECT
    return string.format("%s — %s — %s", dateText, zone, name)
end

function FT:BuildSessionTitle(session)
    return D:BuildSessionTitle(session)
end

function D:CreateSession()
    local charKey = FT:GetCurrentCharKey()
    local zone, mapID = FT:GetCurrentZoneInfo()
    local name = UnitName("player") or UNKNOWNOBJECT
    local realm = GetNormalizedRealmName() or GetRealmName() or ""

    return {
        id = self:GenerateSessionID(),
        state = "active",
        title = nil,
        charKey = charKey,
        charName = name,
        realm = realm,
        zone = zone,
        mapID = mapID,
        startTime = time(),
        activeSeconds = 0,
        pauseStartedAt = nil,
        pauseReason = nil,
        goldLooted = 0,
        itemValue = 0,
        totalValue = 0,
        items = {},
        itemsCount = 0,
        topItemID = nil,
        topItemLink = nil,
        topItemValue = 0,
    }
end

function D:StartSession()
    local db = self:GetDB()
    local s = db.activeSession

    if s and s.state == "active" then
        return s
    end

    if s and s.state == "paused" then
        return self:ResumeSession()
    end

    s = self:CreateSession()
    s.title = self:BuildSessionTitle(s)
    db.activeSession = s
    return s
end

function D:PauseSession(reason)
    local s = self:GetActiveSession()
    if not s or s.state ~= "active" then return end
    s.state = "paused"
    s.pauseStartedAt = time()
    s.pauseReason = reason or "manual"
    return s
end

function D:ResumeSession()
    local s = self:GetActiveSession()
    if not s or s.state ~= "paused" then return s end

    if s.pauseStartedAt then
        local pausedFor = time() - s.pauseStartedAt
        if pausedFor > 0 then
            s.startTime = (s.startTime or time()) + pausedFor
        end
    end

    s.pauseStartedAt = nil
    s.pauseReason = nil
    s.state = "active"
    return s
end

function D:GetElapsedSeconds(session)
    session = session or self:GetActiveSession()
    if not session then return 0 end

    local now = time()
    if session.state == "paused" and session.pauseStartedAt then
        now = session.pauseStartedAt
    end

    local elapsed = now - (session.startTime or now)
    if elapsed < 0 then elapsed = 0 end
    return elapsed
end

function D:TrimHistory()
    local db = self:GetDB()
    local maxHistory = tonumber(db.config.maxHistory) or 100
    while #db.history > maxHistory do
        table.remove(db.history)
    end
end

function D:BuildHistoryRecord(session)
    if not session then return nil end
    local rec = copyTable(session)
    rec.endTime = (session.state == "paused" and session.pauseStartedAt) or time()
    rec.duration = self:GetElapsedSeconds(session)
    rec.state = "finished"
    rec.title = self:BuildSessionTitle(session)
    rec.itemsCount = tcount(rec.items)
    return rec
end

function D:StopSession()
    local db = self:GetDB()
    local s = db.activeSession
    if not s then return nil end

    local rec = self:BuildHistoryRecord(s)
    if rec then
        table.insert(db.history, 1, rec)
    end

    db.activeSession = nil
    self:TrimHistory()
    return rec
end

function D:ResetSession()
    local db = self:GetDB()
    db.activeSession = nil
end

function D:DeleteHistorySession(sessionID)
    if not sessionID then return end
    local hist = self:GetDB().history
    for i = #hist, 1, -1 do
        if hist[i] and hist[i].id == sessionID then
            table.remove(hist, i)
            return true
        end
    end
    return false
end

function D:DeleteAllHistory()
    self:GetDB().history = {}
end

function D:GetHistory(filterMode)
    local hist = self:GetDB().history or {}
    local out = {}
    local mode = filterMode or (self:GetCharDB().ui.historyFilter or "current")
    local current = FT:GetCurrentCharKey()

    for _, s in ipairs(hist) do
        if mode ~= "current" or s.charKey == current then
            out[#out + 1] = s
        end
    end

    table.sort(out, function(a, b)
        return (a.startTime or 0) > (b.startTime or 0)
    end)

    return out
end

function D:GetHistorySessionByID(sessionID)
    if not sessionID then return nil end
    for _, s in ipairs(self:GetDB().history or {}) do
        if s.id == sessionID then
            return s
        end
    end
    return nil
end

function D:UpdateZone()
    local s = self:GetActiveSession()
    if not s then return end
    local zone, mapID = FT:GetCurrentZoneInfo()
    s.zone = zone
    s.mapID = mapID
end

function D:RecalculateSessionTotals(session)
    session = session or self:GetActiveSession()
    if not session then return end

    local itemValue = 0
    local itemsCount = 0
    local topItemValue = 0
    local topItemID, topItemLink

    for itemID, entry in pairs(session.items or {}) do
        local qty = tonumber(entry.qty) or 0
        local unit = tonumber(entry.unitPrice) or 0
        local total = unit * qty
        entry.totalPrice = total
        itemValue = itemValue + total
        itemsCount = itemsCount + 1

        if total > topItemValue then
            topItemValue = total
            topItemID = itemID
            topItemLink = entry.itemLink
        end
    end

    session.itemValue = itemValue
    session.itemsCount = itemsCount
    session.topItemID = topItemID
    session.topItemLink = topItemLink
    session.topItemValue = topItemValue
    session.totalValue = (tonumber(session.goldLooted) or 0) + itemValue
end

function D:AddMoney(copper)
    local s = self:GetActiveSession()
    if not s or s.state ~= "active" then return end
    copper = tonumber(copper) or 0
    if copper <= 0 then return end
    s.goldLooted = (tonumber(s.goldLooted) or 0) + copper
    s.totalValue = (tonumber(s.itemValue) or 0) + (tonumber(s.goldLooted) or 0)
    return s.goldLooted
end

function D:AddMailMoney(copper)
    local s = self:GetActiveSession()
    if not s or s.state ~= "active" then return end

    copper = tonumber(copper) or 0
    if copper <= 0 then return end

    s.goldLooted = (tonumber(s.goldLooted) or 0) + copper
    s.totalValue = (tonumber(s.itemValue) or 0) + (tonumber(s.goldLooted) or 0)
    return s.goldLooted
end

function FT:AddMailMoney(copper) local v = D:AddMailMoney(copper); FT:RefreshUI(); return v end

function D:AddLootItem(itemLink, quantity, obtainType)
    local s = self:GetActiveSession()
    if not s or s.state ~= "active" then return end
    if not itemLink or itemLink == "" then return end

    local itemID = tonumber(string.match(itemLink, "item:(%d+)"))
    if not itemID then return end

    quantity = tonumber(quantity) or 1
    if quantity < 1 then quantity = 1 end
    obtainType = obtainType or "loot"

    local itemName, itemLink2, quality, _, _, _, _, _, _, icon = GetItemInfo(itemID)
    itemLink = itemLink2 or itemLink

    if not self:IsQualityAllowed(quality) then
        return nil
    end

    local entry = s.items[itemID]
    local isNew = not entry
    local oldTotal = entry and (tonumber(entry.totalPrice) or 0) or 0

    local unitPrice, source
    if entry and (tonumber(entry.unitPrice) or 0) > 0 then
        unitPrice = tonumber(entry.unitPrice) or 0
        source = entry.source or "VENDOR"
    else
        unitPrice, source = FT:GetItemPrice(itemID, itemLink)
    end

    local now = time()
    if not entry then
        entry = {
            itemID = itemID,
            itemLink = itemLink,
            itemName = itemName,
            icon = icon or 134400,
            quality = quality or 0,
            qty = 0,
            unitPrice = unitPrice or 0,
            totalPrice = 0,
            source = source or "VENDOR",
            obtainTypes = {},
            firstLootTime = now,
            lastLootTime = now,
        }
        s.items[itemID] = entry
    end

    entry.itemLink = itemLink or entry.itemLink
    entry.itemName = itemName or entry.itemName
    entry.icon = icon or entry.icon or 134400
    entry.quality = quality or entry.quality or 0
    entry.qty = (tonumber(entry.qty) or 0) + quantity
    entry.lastLootTime = now
    entry.obtainTypes = entry.obtainTypes or {}
    entry.obtainTypes[obtainType] = true

    if unitPrice and unitPrice > 0 then
        entry.unitPrice = unitPrice
        entry.source = source or entry.source
    end

    local newTotal = (tonumber(entry.unitPrice) or 0) * (tonumber(entry.qty) or 0)
    entry.totalPrice = newTotal

    if isNew then
        s.itemsCount = (tonumber(s.itemsCount) or 0) + 1
    end

    s.itemValue = (tonumber(s.itemValue) or 0) + (newTotal - oldTotal)
    if s.itemValue < 0 then s.itemValue = 0 end
    s.totalValue = (tonumber(s.goldLooted) or 0) + (tonumber(s.itemValue) or 0)

    if newTotal >= (tonumber(s.topItemValue) or 0) then
        s.topItemID = itemID
        s.topItemLink = entry.itemLink
        s.topItemValue = newTotal
    end

    return entry
end

function D:RefreshPendingPrices(session)
    session = session or self:GetActiveSession()
    if not session then return end

    local changed = false
    for itemID, entry in pairs(session.items or {}) do
        if (tonumber(entry.unitPrice) or 0) <= 0 then
            local price, source = FT:GetItemPrice(itemID, entry.itemLink)
            if price and price > 0 then
                entry.unitPrice = price
                entry.source = source or entry.source
                changed = true
            end
        end
    end

    if changed then
        self:RecalculateSessionTotals(session)
    end
    return changed
end

function FT:GetActiveSession() return D:GetActiveSession() end
function FT:GetSessionState() return D:GetSessionState() end
function FT:IsSessionActive() return D:IsSessionActive() end
function FT:IsSessionPaused() return D:IsSessionPaused() end
function FT:StartSession() local s = D:StartSession(); FT:RefreshUI(true); if s then FT.Print(L["FT_SessionStarted"] or "Session started") end return s end
function FT:PauseSession() local s = D:PauseSession(); FT:RefreshUI(true); if s then FT.Print(L["FT_SessionPaused"] or "Session paused") end return s end
function FT:ResumeSession() local s = D:ResumeSession(); FT:RefreshUI(true); if s then FT.Print(L["FT_SessionResumed"] or "Session resumed") end return s end
function FT:StopSession() local r = D:StopSession(); FT:RefreshUI(true); if r then FT.Print(L["FT_SessionStopped"] or "Session stopped") end return r end
function FT:ResetSession() D:ResetSession(); FT:RefreshUI(true); FT.Print(L["FT_SessionReset"] or "Session reset") end
function FT:AddMoney(copper) local v = D:AddMoney(copper); FT:RefreshUI(); return v end
function FT:AddLootItem(itemLink, quantity, obtainType) local v = D:AddLootItem(itemLink, quantity, obtainType); FT:RefreshUI(); return v end
function FT:IsSourceEnabled(kind) return D:IsSourceEnabled(kind) end
function FT:RecalculateSessionTotals() local s = D:GetActiveSession(); D:RecalculateSessionTotals(s); FT:RefreshUI(true) end
function FT:GetHistory(filterMode) return D:GetHistory(filterMode) end
function FT:GetHistorySessionByID(sessionID) return D:GetHistorySessionByID(sessionID) end
function FT:DeleteHistorySession(sessionID) local ok = D:DeleteHistorySession(sessionID); FT:RefreshUI(true); return ok end
function FT:DeleteAllHistory() D:DeleteAllHistory(); FT:RefreshUI(true) end
