/**
 * @license
 * Copyright 2026 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */

import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import { randomUUID } from 'node:crypto';
import { testTruncateProfile } from './testing/testProfile.js';
import {
  createSyntheticHistory,
  createMockContextConfig,
  setupContextComponentTest,
  deriveStableId,
} from './testing/contextTestUtils.js';

describe('ContextManager Sync Pressure Barrier Tests', () => {
  beforeEach(() => {
    vi.useFakeTimers();
  });

  afterEach(() => {
    vi.useRealTimers();
    vi.restoreAllMocks();
  });

  it('should instantly truncate history when maxTokens is exceeded using truncate strategy', async () => {
    // 1. Setup
    const config = createMockContextConfig();
    const { chatHistory, contextManager } = setupContextComponentTest(
      config,
      testTruncateProfile,
    );

    // 2. Add System Prompt (Episode 0 - Protected)
    const envId = deriveStableId(['environment-context']);
    chatHistory.set([
      {
        id: envId,
        content: {
          role: 'user',
          parts: [{ text: '<session_context>\nSystem prompt' }],
        },
      },
      {
        id: 'h2',
        content: { role: 'model', parts: [{ text: 'Understood.' }] },
      },
    ]);

    // 3. Add massive history that blows past the 150k maxTokens limit
    // 20 turns * ~20,000 tokens/turn (10k user + 10k model) = ~400,000 tokens
    const massiveHistory = createSyntheticHistory(20, 10000).map((c) => ({
      id: randomUUID(),
      content: c,
    }));
    chatHistory.set([...chatHistory.get(), ...massiveHistory]);

    // 4. Add the Latest Turn (Protected)
    chatHistory.set([
      ...chatHistory.get(),
      {
        id: 'h-last-user',
        content: { role: 'user', parts: [{ text: 'Final question.' }] },
      },
      {
        id: 'h-last-model',
        content: { role: 'model', parts: [{ text: 'Final answer.' }] },
      },
    ]);

    const rawHistoryLength = chatHistory.get().length;

    // 5. Project History (Triggers Sync Barrier)
    const { history: projection } = await contextManager.renderHistory();

    // 6. Assertions
    // The barrier should have dropped several older episodes to get under 150k.

    expect(projection.length).toBeLessThan(rawHistoryLength);

    // Verify Episode 0 (System) was PRESERVED because it is pinned Turn 0.
    expect(projection[0].id).toBe(envId);
    expect(projection[0].content.role).toBe('user');

    const projectionString = JSON.stringify(projection);
    expect(projectionString).toContain('User turn 17');
    // Filter out synthetic Yield nodes (they are model responses without actual tool/text bodies)
    const contentNodes = projection.filter(
      (p) =>
        p.content.parts &&
        p.content.parts.some((part) => part.text && part.text !== 'Yield'),
    );

    // Verify the latest turn is perfectly preserved at the back
    const lastModel = contentNodes[contentNodes.length - 1].content;
    const lastUser = contentNodes[contentNodes.length - 2].content;

    expect(lastModel.role).toBe('model');
    expect(lastModel.parts![0].text).toBe('Final answer.');

    expect(lastUser.role).toBe('user');
    expect(lastUser.parts![0].text).toBe('Final question.');
  });
});
