-- ============================================================================
-- Vamoose's Companion - Bonding Engine
-- Per-companion rapport tracking. Persisted via Store.
-- Adapted from archive/VamooseAssistant 2/Intelligence/VA_RelationshipEngine.lua
-- ============================================================================

VC = VC or {}
VC.Bonding = {
    initialized = false,
}

-- ============================================================================
-- INITIALIZATION
-- ============================================================================

function VC.Bonding:Initialize()
    if self.initialized then return end

    -- Ensure active companion has bonding state
    local activeKey = VC.Store:GetState().config.activeCompanion
    self:EnsureState(activeKey)

    -- Process daily login for active companion
    self:ProcessDailyLogin(activeKey)

    -- Long-session check every 60 seconds (handle kept so a future disable
    -- path can cancel it; re-Initialize won't stack a second ticker)
    if not self._sessionTicker then
        self._sessionTicker = C_Timer.NewTicker(60, function()
            self:CheckSessionBonus()
        end)
    end

    self.initialized = true
end

-- ============================================================================
-- STATE HELPERS
-- ============================================================================

function VC.Bonding:EnsureState(companionKey)
    local bonding = VC.Store:GetState().bonding
    if not bonding[companionKey] then
        VC.Store:Dispatch("SET_BONDING_LOGIN", {
            companionKey = companionKey,
            streakDays = 0, lastStreakDay = nil, lastLoginTime = 0,
        })
    end
end

-- ============================================================================
-- RAPPORT CHANGES
-- ============================================================================

function VC.Bonding:AddRapport(amount, reason)
    local activeKey = VC.Store:GetState().config.activeCompanion
    self:EnsureState(activeKey)

    -- Snapshot old level for transition detection
    local oldBond = VC.Store:GetState().bonding[activeKey]
    local oldLevel = oldBond and oldBond.level or "Stranger"

    VC.Store:Dispatch("ADD_RAPPORT", {
        companionKey = activeKey,
        amount = amount,
        reason = reason,
    })

    -- Check for bond level-up
    local newLevel = VC.Store:GetState().bonding[activeKey].level
    if newLevel ~= oldLevel then
        VC.EventBus:Trigger("VC_BOND_LEVEL_UP", {
            companionKey = activeKey,
            oldLevel = oldLevel,
            newLevel = newLevel,
        })
    end

    if VC.Store:GetState().config.debug then
        local b = VC.Store:GetState().bonding[activeKey]
        print(format("|cFFA0522D[VC Bond]|r %s%d (%s) -> %d (%s)",
            amount >= 0 and "+" or "", amount, reason or "?",
            b.rapport, b.level))
    end
end

-- ============================================================================
-- DAILY LOGIN PROCESSING
-- ============================================================================

function VC.Bonding:ProcessDailyLogin(companionKey)
    local bonding = VC.Store:GetState().bonding
    local b = bonding[companionKey]
    if not b then return end

    local today = date("%Y%m%d")
    local now = time()

    -- Already processed today
    if b.lastDay == today and b.lastLoginTime > 0 then return end

    -- Calculate days since last login
    local daysSinceLogin = 0
    if b.lastLoginTime > 0 then
        daysSinceLogin = math.floor((now - b.lastLoginTime) / 86400)
    end

    -- Calculate new streak values
    local newStreakDays, newLastStreakDay
    if daysSinceLogin <= 1 then
        if b.lastStreakDay ~= today then
            newStreakDays = (b.streakDays or 0) + 1
            newLastStreakDay = today
        end
    else
        newStreakDays = 1
        newLastStreakDay = today
    end

    -- Dispatch streak/login update via reducer (no direct mutation)
    VC.Store:Dispatch("SET_BONDING_LOGIN", {
        companionKey = companionKey,
        streakDays = newStreakDays or b.streakDays,
        lastStreakDay = newLastStreakDay or b.lastStreakDay,
        lastLoginTime = now,
    })

    -- Re-read state after dispatch
    b = VC.Store:GetState().bonding[companionKey]

    -- Daily login bonus (bypasses cap)
    VC.Store:Dispatch("ADD_RAPPORT", {
        companionKey = companionKey,
        amount = VC.Constants.BONDING.GAINS.DAILY_LOGIN,
        reason = "daily_login",
        ignoreCap = true,
    })

    -- Streak bonus (3+ days)
    if b.streakDays >= 3 then
        VC.Store:Dispatch("ADD_RAPPORT", {
            companionKey = companionKey,
            amount = VC.Constants.BONDING.GAINS.LOGIN_STREAK,
            reason = "login_streak",
            ignoreCap = true,
        })
    end

    -- Check streak milestones (7/30/100 day thresholds)
    if VC.Memory then VC.Memory:CheckStreakMilestones(b.streakDays) end

    -- Absence penalty (7+ days away)
    if daysSinceLogin >= 7 then
        local weeks = math.floor(daysSinceLogin / 7)
        VC.Store:Dispatch("ADD_RAPPORT", {
            companionKey = companionKey,
            amount = VC.Constants.BONDING.ABSENCE_PENALTY * weeks,
            reason = "absence",
            ignoreCap = true,
        })
    end
end

-- ============================================================================
-- SESSION BONUS
-- ============================================================================

function VC.Bonding:CheckSessionBonus()
    if not VC._sessionStart then return end
    local duration = GetTime() - VC._sessionStart
    if duration < 1800 then return end -- 30 min

    if self._sessionBonusAwarded then return end
    self._sessionBonusAwarded = true

    self:AddRapport(VC.Constants.BONDING.GAINS.LONG_SESSION, "long_session")
end

-- ============================================================================
-- GETTERS
-- ============================================================================

function VC.Bonding:GetLevel(companionKey)
    companionKey = companionKey or VC.Store:GetState().config.activeCompanion
    local b = VC.Store:GetState().bonding[companionKey]
    return b and b.level or "Stranger"
end

function VC.Bonding:GetLevelInfo(companionKey)
    companionKey = companionKey or VC.Store:GetState().config.activeCompanion
    local b = VC.Store:GetState().bonding[companionKey]
    if not b then
        return { name = "Stranger", rapport = 0, progress = 0, nextThreshold = 100 }
    end

    local LEVELS = VC.Constants.BONDING.LEVELS
    local currentLevel, nextLevel
    for i, lvl in ipairs(LEVELS) do
        if b.rapport >= lvl.threshold then
            currentLevel = lvl
            nextLevel = LEVELS[i + 1]
        end
    end

    if not currentLevel then
        currentLevel = LEVELS[1]
        nextLevel = LEVELS[2]
    end

    local progress = 0
    if nextLevel then
        local range = nextLevel.threshold - currentLevel.threshold
        local current = b.rapport - currentLevel.threshold
        progress = math.min(1, current / range)
    else
        progress = 1
    end

    return {
        name = currentLevel.name,
        rapport = b.rapport,
        progress = progress,
        nextThreshold = nextLevel and nextLevel.threshold or nil,
        streakDays = b.streakDays or 0,
    }
end
