import { describe, it, expect, vi } from 'vitest'
import { MemoryManager, truncateToolResult } from '../manager'
import type { AgentMemory } from '../types'
import type { AgentScopedLogger } from '../../observability/logging'

describe('MemoryManager', () => {
  const createMockLogger = (): AgentScopedLogger => ({
    action: vi.fn(),
    lifecycle: vi.fn(),
    memory: vi.fn(),
    tool: vi.fn(),
    reasoning: vi.fn()
  })

  const createEmptyMemory = (): AgentMemory => ({
    sessionMemory: {},
    history: []
  })

  describe('set() - Agent operations', () => {
    it('sets session memory entry', () => {
      const memory = createEmptyMemory()
      const manager = new MemoryManager(memory)

      manager.set('task', 'Build user registration flow')

      expect(memory.sessionMemory['task']).toBeDefined()
      expect(memory.sessionMemory['task'].type).toBe('context')
      expect(memory.sessionMemory['task'].content).toBe('Build user registration flow')
    })

    it('adds timestamp to entry', () => {
      const memory = createEmptyMemory()
      const manager = new MemoryManager(memory)

      const beforeTimestamp = Date.now()
      manager.set('note', 'Test note')
      const afterTimestamp = Date.now()

      expect(memory.sessionMemory['note'].timestamp).toBeGreaterThanOrEqual(beforeTimestamp)
      expect(memory.sessionMemory['note'].timestamp).toBeLessThanOrEqual(afterTimestamp)
    })

    it('overwrites existing key with same name', () => {
      const memory = createEmptyMemory()
      const manager = new MemoryManager(memory)

      manager.set('counter', '1')
      manager.set('counter', '2')

      expect(memory.sessionMemory['counter'].content).toBe('2')
      expect(Object.keys(memory.sessionMemory)).toHaveLength(1)
    })

    it('truncates entry exceeding single entry token limit', () => {
      const memory = createEmptyMemory()
      const logger = createMockLogger()
      const manager = new MemoryManager(memory, {}, logger)

      // 2000 tokens * 4 chars/token = 8000 chars, create 10000 chars
      const largeContent = 'a'.repeat(10000)
      manager.set('large', largeContent)

      expect(memory.sessionMemory['large'].content).toContain('[truncated]')
      expect(memory.sessionMemory['large'].content.length).toBeLessThan(largeContent.length)
      expect(logger.action).toHaveBeenCalledWith(
        'memory-truncate',
        expect.stringContaining('Single entry exceeds token limit'),
        expect.anything(),
        expect.anything(),
        expect.anything(),
        expect.anything()
      )
    })

    it('handles multiple session memory keys', () => {
      const memory = createEmptyMemory()
      const manager = new MemoryManager(memory)

      manager.set('task', 'Build feature')
      manager.set('context', 'User story...')
      manager.set('progress', 'Step 1 done')

      expect(Object.keys(memory.sessionMemory)).toHaveLength(3)
      expect(memory.sessionMemory['task']).toBeDefined()
      expect(memory.sessionMemory['context']).toBeDefined()
      expect(memory.sessionMemory['progress']).toBeDefined()
    })
  })

  describe('delete() - Agent operations', () => {
    it('deletes existing session memory entry', () => {
      const memory = createEmptyMemory()
      const manager = new MemoryManager(memory)

      manager.set('temp', 'temporary data')
      const result = manager.delete('temp')

      expect(result).toBe(true)
      expect(memory.sessionMemory['temp']).toBeUndefined()
    })

    it('returns false for non-existent key', () => {
      const memory = createEmptyMemory()
      const manager = new MemoryManager(memory)

      const result = manager.delete('nonexistent')

      expect(result).toBe(false)
    })

    it('does not affect other keys when deleting', () => {
      const memory = createEmptyMemory()
      const manager = new MemoryManager(memory)

      manager.set('keep1', 'data1')
      manager.set('delete-me', 'data2')
      manager.set('keep2', 'data3')

      manager.delete('delete-me')

      expect(Object.keys(memory.sessionMemory)).toHaveLength(2)
      expect(memory.sessionMemory['keep1']).toBeDefined()
      expect(memory.sessionMemory['keep2']).toBeDefined()
    })
  })

  describe('addToHistory() - Framework operations', () => {
    it('adds entry to history with iteration number', () => {
      const memory = createEmptyMemory()
      const manager = new MemoryManager(memory)

      const entry = {
        type: 'reasoning' as const,
        content: 'Thinking about the problem...',
        timestamp: Date.now()
      }

      manager.addToHistory({ ...entry, turnNumber: null, iterationNumber: 1 })

      expect(memory.history).toHaveLength(1)
      expect(memory.history[0].type).toBe('reasoning')
      expect(memory.history[0].content).toBe('Thinking about the problem...')
      expect(memory.history[0].iterationNumber).toBe(1)
    })

    it('appends multiple entries in order', () => {
      const memory = createEmptyMemory()
      const manager = new MemoryManager(memory)

      const entry1 = { type: 'input' as const, content: 'User request', timestamp: Date.now() }
      const entry2 = { type: 'reasoning' as const, content: 'Agent thinking', timestamp: Date.now() }
      const entry3 = { type: 'tool-result' as const, content: 'Tool output', timestamp: Date.now() }

      manager.addToHistory({ ...entry1, turnNumber: null, iterationNumber: 0 })
      manager.addToHistory({ ...entry2, turnNumber: null, iterationNumber: 1 })
      manager.addToHistory({ ...entry3, turnNumber: null, iterationNumber: 1 })

      expect(memory.history).toHaveLength(3)
      expect(memory.history[0].type).toBe('input')
      expect(memory.history[1].type).toBe('reasoning')
      expect(memory.history[2].type).toBe('tool-result')
    })

    it('triggers auto-compact when at 100% token budget', () => {
      const memory = createEmptyMemory()
      const manager = new MemoryManager(memory, { maxMemoryTokens: 100 })

      // Add first entry (will be preserved as anchor)
      manager.addToHistory({ type: 'input', content: 'First', turnNumber: null, iterationNumber: 0 })

      // Add many entries to exceed token budget
      for (let i = 0; i < 50; i++) {
        manager.addToHistory({
          type: 'reasoning',
          content: 'a'.repeat(100), // ~30 tokens each
          turnNumber: null,
          iterationNumber: 1
        })
      }

      // Should be compacted to first + last 10
      expect(memory.history.length).toBe(11)
      expect(memory.history[0].content).toBe('First')
    })
  })

  describe('autoCompact()', () => {
    it('does not compact when below 100% token budget', () => {
      const memory = createEmptyMemory()
      const manager = new MemoryManager(memory, { maxMemoryTokens: 10000 })

      // Add a few entries (well below budget)
      for (let i = 0; i < 5; i++) {
        manager.addToHistory({
          type: 'reasoning',
          content: 'Small entry',
          turnNumber: null,
          iterationNumber: 1
        })
      }

      expect(memory.history).toHaveLength(5)
    })

    it('compacts when at exactly 100% token budget', () => {
      const memory = createEmptyMemory()
      const logger = createMockLogger()
      const manager = new MemoryManager(memory, { maxMemoryTokens: 10 }, logger)

      // Add enough entries to reach 100%
      for (let i = 0; i < 20; i++) {
        manager.addToHistory({
          type: 'reasoning',
          content: 'Entry that takes tokens',
          turnNumber: null,
          iterationNumber: 1
        })
      }

      expect(memory.history.length).toBe(11) // First + last 10
      expect(logger.action).toHaveBeenCalledWith(
        'memory-auto-compact',
        expect.stringContaining('Auto-compacted'),
        expect.anything(),
        expect.anything(),
        expect.anything(),
        expect.anything()
      )
    })

    it('preserves first entry (anchor)', () => {
      const memory = createEmptyMemory()
      const manager = new MemoryManager(memory, { maxMemoryTokens: 10 })

      const firstEntry = { type: 'input' as const, content: 'FIRST ENTRY', timestamp: Date.now() }
      manager.addToHistory({ ...firstEntry, turnNumber: null, iterationNumber: 0 })

      // Add many more entries
      for (let i = 0; i < 50; i++) {
        manager.addToHistory({
          type: 'reasoning',
          content: 'Later entry...',
          turnNumber: null,
          iterationNumber: 1
        })
      }

      expect(memory.history[0].type).toBe(firstEntry.type)
      expect(memory.history[0].content).toBe('FIRST ENTRY')
    })

    it('preserves last 10 entries', () => {
      const memory = createEmptyMemory()
      const manager = new MemoryManager(memory, { maxMemoryTokens: 10 })

      manager.addToHistory({ type: 'input', content: 'First', turnNumber: null, iterationNumber: 0 })

      const lastEntries: { type: 'reasoning'; content: string; timestamp: number }[] = []
      // Add middle entries that will be removed
      for (let i = 0; i < 20; i++) {
        manager.addToHistory({ type: 'reasoning', content: `Middle ${i}`, turnNumber: null, iterationNumber: 1 })
      }

      // Add last 10 entries to preserve
      for (let i = 0; i < 10; i++) {
        const entry = { type: 'reasoning' as const, content: `Last ${i}`, timestamp: Date.now() }
        lastEntries.push(entry)
        manager.addToHistory({ ...entry, turnNumber: null, iterationNumber: 2 })
      }

      expect(memory.history).toHaveLength(11) // First + 10
      // Verify last 10 are preserved
      for (let i = 0; i < 10; i++) {
        expect(memory.history[i + 1].content).toBe(lastEntries[i].content)
        expect(memory.history[i + 1].type).toBe(lastEntries[i].type)
      }
    })
  })

  describe('enforceHardLimits()', () => {
    it('removes oldest session memory entries when exceeding limit', () => {
      const memory = createEmptyMemory()
      const logger = createMockLogger()
      const manager = new MemoryManager(memory, { maxSessionMemoryKeys: 3 }, logger)

      // Add entries with specific timestamps
      manager.set('key1', 'oldest')
      manager.set('key2', 'middle')
      manager.set('key3', 'recent')
      manager.set('key4', 'newest')

      manager.enforceHardLimits()

      expect(Object.keys(memory.sessionMemory)).toHaveLength(3)
      expect(memory.sessionMemory['key1']).toBeUndefined() // Oldest removed
      expect(memory.sessionMemory['key2']).toBeDefined()
      expect(memory.sessionMemory['key3']).toBeDefined()
      expect(memory.sessionMemory['key4']).toBeDefined()
    })

    it('logs when session memory limit exceeded', () => {
      const memory = createEmptyMemory()
      const logger = createMockLogger()
      const manager = new MemoryManager(memory, { maxSessionMemoryKeys: 2 }, logger)

      manager.set('key1', 'data1')
      manager.set('key2', 'data2')
      manager.set('key3', 'data3')

      manager.enforceHardLimits()

      expect(logger.action).toHaveBeenCalledWith(
        'memory-limit-exceeded',
        expect.stringContaining('Session memory exceeds hard limit'),
        expect.anything(),
        expect.anything(),
        expect.anything(),
        expect.anything()
      )
    })

    it('performs emergency compaction when exceeding total token budget', () => {
      const memory = createEmptyMemory()
      const logger = createMockLogger()
      const manager = new MemoryManager(memory, { maxMemoryTokens: 20 }, logger)

      // Add first entry (will be preserved)
      manager.addToHistory({ type: 'input', content: 'First', turnNumber: null, iterationNumber: 0 })

      // Add many entries to exceed budget
      for (let i = 0; i < 100; i++) {
        manager.addToHistory({
          type: 'reasoning',
          content: 'a'.repeat(200),
          turnNumber: null,
          iterationNumber: 1
        })
      }

      manager.enforceHardLimits()

      // Emergency compaction: first + last 5 = 6 total
      expect(memory.history.length).toBe(6)
      // Check that memory-emergency was called at some point
      const emergencyCalls = (logger.action as unknown as { mock: { calls: unknown[][] } }).mock.calls.filter(
        (call: unknown[]) => call[0] === 'memory-emergency'
      )
      expect(emergencyCalls.length).toBeGreaterThan(0)
      expect(emergencyCalls[0][1]).toContain('Total memory exceeds token budget')
    })

    it('uses default hard limits when no constraints provided', () => {
      const memory = createEmptyMemory()
      const manager = new MemoryManager(memory)

      // Default MAX_SESSION_MEMORY_KEYS is 25
      for (let i = 0; i < 27; i++) {
        manager.set(`key${i}`, `data${i}`)
      }

      manager.enforceHardLimits()

      expect(Object.keys(memory.sessionMemory)).toHaveLength(25)
    })
  })

  describe('getHistoryLength()', () => {
    it('returns 0 for empty history', () => {
      const memory = createEmptyMemory()
      const manager = new MemoryManager(memory)

      expect(manager.getHistoryLength()).toBe(0)
    })

    it('returns correct count after adding entries', () => {
      const memory = createEmptyMemory()
      const manager = new MemoryManager(memory)

      manager.addToHistory({ type: 'input', content: 'Entry 1', turnNumber: null, iterationNumber: 0 })
      expect(manager.getHistoryLength()).toBe(1)

      manager.addToHistory({ type: 'reasoning', content: 'Entry 2', turnNumber: null, iterationNumber: 1 })
      expect(manager.getHistoryLength()).toBe(2)

      manager.addToHistory({ type: 'tool-result', content: 'Entry 3', turnNumber: null, iterationNumber: 1 })
      expect(manager.getHistoryLength()).toBe(3)
    })
  })

  describe('getStatus()', () => {
    it('returns status with all fields', () => {
      const memory = createEmptyMemory()
      const manager = new MemoryManager(memory)

      const status = manager.getStatus()

      expect(status).toHaveProperty('sessionMemoryKeys')
      expect(status).toHaveProperty('sessionMemoryLimit')
      expect(status).toHaveProperty('currentKeys')
      expect(status).toHaveProperty('historyPercent')
      expect(status).toHaveProperty('historyTokens')
      expect(status).toHaveProperty('tokenBudget')
    })

    it('calculates session memory key count correctly', () => {
      const memory = createEmptyMemory()
      const manager = new MemoryManager(memory)

      manager.set('key1', 'data1')
      manager.set('key2', 'data2')
      manager.set('key3', 'data3')

      const status = manager.getStatus()

      expect(status.sessionMemoryKeys).toBe(3)
      expect(status.currentKeys).toEqual(['key1', 'key2', 'key3'])
    })

    it('calculates token usage percentage', () => {
      const memory = createEmptyMemory()
      const manager = new MemoryManager(memory, { maxMemoryTokens: 100 })

      // Add entry that takes ~50 tokens (50 chars * 4 = ~12 tokens * 1.2 = ~15 tokens)
      manager.addToHistory({
        type: 'input',
        content: 'a'.repeat(200), // ~60 tokens
        turnNumber: null,
        iterationNumber: 0
      })

      const status = manager.getStatus()

      expect(status.historyPercent).toBeGreaterThan(0)
      expect(status.historyPercent).toBeLessThanOrEqual(100)
      expect(status.tokenBudget).toBe(100)
    })

    it('includes session memory and history tokens in total', () => {
      const memory = createEmptyMemory()
      const manager = new MemoryManager(memory, { maxMemoryTokens: 1000 })

      manager.set('persistent1', 'a'.repeat(100))
      manager.addToHistory({ type: 'input', content: 'a'.repeat(100), turnNumber: null, iterationNumber: 0 })

      const status = manager.getStatus()

      expect(status.historyTokens).toBeGreaterThan(0)
    })
  })

  describe('toSnapshot() and getSnapshot()', () => {
    it('creates deep copy of memory', () => {
      const memory = createEmptyMemory()
      const manager = new MemoryManager(memory)

      manager.set('key', 'value')
      manager.addToHistory({ type: 'input', content: 'test', turnNumber: null, iterationNumber: 0 })

      const snapshot = manager.toSnapshot()

      // Modify original
      manager.set('key', 'modified')
      manager.addToHistory({ type: 'reasoning', content: 'new', turnNumber: null, iterationNumber: 1 })

      // Snapshot should not be affected
      expect(snapshot.sessionMemory['key'].content).toBe('value')
      expect(snapshot.history).toHaveLength(1)
    })

    it('caches snapshot for later retrieval', () => {
      const memory = createEmptyMemory()
      const manager = new MemoryManager(memory)

      manager.set('data', 'test')

      const snapshot1 = manager.toSnapshot()
      const snapshot2 = manager.getSnapshot()

      expect(snapshot2).toBe(snapshot1)
    })

    it('returns undefined if toSnapshot not called yet', () => {
      const memory = createEmptyMemory()
      const manager = new MemoryManager(memory)

      expect(manager.getSnapshot()).toBeUndefined()
    })
  })

  describe('toContext()', () => {
    it('generates formatted context string with iteration filtering', () => {
      const memory = createEmptyMemory()
      const manager = new MemoryManager(memory)

      const context = manager.toContext(1)

      expect(context).toContain('MEMORY STATUS')
      expect(context).toContain('SESSION MEMORY')
      expect(context).toContain('ITERATION 1 - CURRENT CONTEXT')
      expect(context).toContain('EARLIER CONTEXT')
    })

    it('includes session memory entries with keys', () => {
      const memory = createEmptyMemory()
      const manager = new MemoryManager(memory)

      manager.set('task', 'Build feature X')
      manager.set('context', 'User requested...')

      const context = manager.toContext(1)

      expect(context).toContain('[SESSION:task]')
      expect(context).toContain('Build feature X')
      expect(context).toContain('[SESSION:context]')
      expect(context).toContain('User requested...')
    })

    it('filters history by iteration - current context reversed', () => {
      const memory = createEmptyMemory()
      const manager = new MemoryManager(memory)

      manager.addToHistory({ type: 'input', content: 'User input', turnNumber: null, iterationNumber: 0 })
      manager.addToHistory({ type: 'reasoning', content: 'First reasoning', turnNumber: null, iterationNumber: 1 })
      manager.addToHistory({ type: 'tool-result', content: 'Tool result', turnNumber: null, iterationNumber: 1 })

      const context = manager.toContext(1)

      // Current iteration (1) entries should appear reversed (tool result first)
      const currentSection = context
        .split('=== ITERATION 1 - CURRENT CONTEXT ===')[1]
        .split('=== EARLIER CONTEXT ===')[0]
      expect(currentSection.indexOf('TOOL-RESULT')).toBeLessThan(currentSection.indexOf('REASONING'))

      // Earlier context (iteration 0) should appear after
      const earlierSection = context.split('=== EARLIER CONTEXT ===')[1]
      expect(earlierSection).toContain('[INPUT]')
      expect(earlierSection).toContain('User input')
    })

    it('shows empty message when no session memory entries', () => {
      const memory = createEmptyMemory()
      const manager = new MemoryManager(memory)

      const context = manager.toContext(1)

      expect(context).toContain('(empty)')
    })

    it('shows no earlier context message for iteration 0', () => {
      const memory = createEmptyMemory()
      const manager = new MemoryManager(memory)

      manager.addToHistory({ type: 'input', content: 'test', turnNumber: null, iterationNumber: 0 })

      const context = manager.toContext(0)

      expect(context).toContain('(no earlier context)')
    })

    it('handles turn-scoped iteration filtering correctly', () => {
      const memory = createEmptyMemory()
      const manager = new MemoryManager(memory)

      // Turn 1 entries
      manager.addToHistory({ type: 'input', turnNumber: 1, iterationNumber: 0, content: 'Turn 1 input' })
      manager.addToHistory({ type: 'reasoning', turnNumber: 1, iterationNumber: 1, content: 'Turn 1 reasoning' })

      // Turn 2 entries
      manager.addToHistory({ type: 'input', turnNumber: 2, iterationNumber: 0, content: 'Turn 2 input' })
      manager.addToHistory({ type: 'reasoning', turnNumber: 2, iterationNumber: 1, content: 'Turn 2 reasoning' })

      // Turn 2, Iteration 1 - should ONLY see Turn 2's context
      const context = manager.toContext(1, 2)

      // Assert: Current context contains ONLY Turn 2's iteration 1
      expect(context).toContain('Turn 2 reasoning')
      expect(context).not.toContain('Turn 1 reasoning')

      // Assert: Earlier context contains ONLY Turn 2's iteration 0
      expect(context).toContain('Turn 2 input')
      expect(context).not.toContain('Turn 1 input')
    })

    it('handles one-off executions without turnNumber', () => {
      const memory = createEmptyMemory()
      const manager = new MemoryManager(memory)

      manager.addToHistory({ type: 'input', turnNumber: null, iterationNumber: 0, content: 'Input' })
      manager.addToHistory({ type: 'reasoning', turnNumber: null, iterationNumber: 1, content: 'Reasoning' })

      // One-off execution - toContext() called without currentTurn parameter
      const context = manager.toContext(1)

      // Should work as before (no turn filtering)
      expect(context).toContain('Reasoning')
      expect(context).toContain('Input')
    })

    it('handles legacy entries without turnNumber gracefully', () => {
      const memory: AgentMemory = {
        sessionMemory: {},
        history: [
          // Legacy entries (pre-migration) without turnNumber
          {
            type: 'input',
            content: 'Legacy input',
            timestamp: 1,
            turnNumber: undefined as unknown as null,
            iterationNumber: 0
          },
          {
            type: 'reasoning',
            content: 'Legacy reasoning',
            timestamp: 2,
            turnNumber: undefined as unknown as null,
            iterationNumber: 1
          },
          // New entries with turnNumber
          { type: 'input', content: 'New input', timestamp: 3, turnNumber: 2, iterationNumber: 0 },
          { type: 'reasoning', content: 'New reasoning', timestamp: 4, turnNumber: 2, iterationNumber: 1 }
        ]
      }

      const manager = new MemoryManager(memory)

      // Turn 2, Iteration 1 - should see both legacy (undefined treated as valid) and Turn 2 entries
      const context = manager.toContext(1, 2)

      // Should include Turn 2's entries
      expect(context).toContain('New reasoning')

      // Should also include legacy entries (backward compatibility)
      expect(context).toContain('Legacy reasoning')
    })
  })
})

describe('truncateToolResult()', () => {
  it('returns content unchanged when under the token limit', () => {
    const content = 'short result'
    const result = truncateToolResult(content, 4_000)
    expect(result).toBe(content)
  })

  it('truncates content that exceeds the token limit', () => {
    // 4000 tokens * 3.5 chars/token = 14000 chars; create 20000 chars to exceed
    const content = 'x'.repeat(20_000)
    const result = truncateToolResult(content, 4_000)

    expect(result.length).toBeLessThan(content.length)
    expect(result).toContain('[Response truncated')
    expect(result).toContain('tokens omitted')
  })

  it('includes the number of omitted tokens in the truncation notice', () => {
    const content = 'a'.repeat(21_000) // ~6000 tokens at 3.5 chars/token
    const result = truncateToolResult(content, 4_000)

    // Should mention roughly 2000 omitted tokens
    expect(result).toContain('tokens omitted')
  })

  it('returns content unchanged when exactly at the limit', () => {
    // 4000 tokens * 3.5 = 14000 chars exactly
    const content = 'b'.repeat(14_000)
    const result = truncateToolResult(content, 4_000)
    expect(result).toBe(content)
  })
})

describe('MemoryManager - tool result truncation in addToHistory', () => {
  const createMockLogger = (): AgentScopedLogger =>
    ({
      action: vi.fn(),
      lifecycle: vi.fn(),
      memory: vi.fn(),
      tool: vi.fn(),
      reasoning: vi.fn()
    }) as unknown as AgentScopedLogger

  const createEmptyMemory = (): AgentMemory => ({
    sessionMemory: {},
    history: []
  })

  it('truncates tool-result entries exceeding MAX_TOOL_RESULT_TOKENS', () => {
    const memory = createEmptyMemory()
    const logger = createMockLogger()
    const manager = new MemoryManager(memory, {}, logger)

    // 4000 tokens * 3.5 = 14000 chars; create 28000 chars (~8000 tokens)
    const largeContent = 'z'.repeat(28_000)

    manager.addToHistory({
      type: 'tool-result',
      content: largeContent,
      turnNumber: null,
      iterationNumber: 1
    })

    expect(memory.history).toHaveLength(1)
    expect(memory.history[0].content.length).toBeLessThan(largeContent.length)
    expect(memory.history[0].content).toContain('[Response truncated')
    expect(logger.action).toHaveBeenCalledWith(
      'memory-tool-result-truncate',
      expect.stringContaining('Tool result truncated'),
      expect.anything(),
      expect.anything(),
      expect.anything(),
      expect.anything()
    )
  })

  it('does not truncate tool-result entries under the limit', () => {
    const memory = createEmptyMemory()
    const manager = new MemoryManager(memory)

    const smallContent = '{"status": "ok"}'
    manager.addToHistory({
      type: 'tool-result',
      content: smallContent,
      turnNumber: null,
      iterationNumber: 1
    })

    expect(memory.history[0].content).toBe(smallContent)
  })

  it('does not truncate non-tool-result entries regardless of size', () => {
    const memory = createEmptyMemory()
    const manager = new MemoryManager(memory, { maxMemoryTokens: 100_000 })

    const largeReasoning = 'r'.repeat(28_000)
    manager.addToHistory({
      type: 'reasoning',
      content: largeReasoning,
      turnNumber: null,
      iterationNumber: 1
    })

    expect(memory.history[0].content).toBe(largeReasoning)

    const largeInput = 'i'.repeat(28_000)
    manager.addToHistory({
      type: 'input',
      content: largeInput,
      turnNumber: null,
      iterationNumber: 0
    })

    expect(memory.history[1].content).toBe(largeInput)
  })
})
