import { type UIChatMessage } from '@lobechat/types';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';

import * as isCanUseFCModule from '@/helpers/isCanUseFC';
import { agentService } from '@/services/agent';
import { agentDocumentService } from '@/services/agentDocument';
import { useAgentStore } from '@/store/agent';

import * as helpers from '../helper';
import { contextEngineering } from './contextEngineering';
import * as memoryManager from './memoryManager';

vi.hoisted(() => {
  const storage = new Map<string, string>();

  Object.defineProperty(globalThis, 'localStorage', {
    configurable: true,
    value: {
      clear: () => storage.clear(),
      getItem: (key: string) => storage.get(key) ?? null,
      key: (index: number) => Array.from(storage.keys())[index] ?? null,
      get length() {
        return storage.size;
      },
      removeItem: (key: string) => {
        storage.delete(key);
      },
      setItem: (key: string, value: string) => {
        storage.set(key, value);
      },
    },
  });
});

// Mock VARIABLE_GENERATORS
vi.mock('@/helpers/parserPlaceholder', () => ({
  VARIABLE_GENERATORS: {
    date: () => '2023-12-25',
    time: () => '14:30:45',
    username: () => 'TestUser',
    random: () => '12345',
  },
}));

vi.mock('@/services/agentDocument', () => ({
  agentDocumentService: {
    getDocuments: vi.fn(),
  },
}));

vi.mock('@/services/agent', () => ({
  AVAILABLE_AGENTS_CONTEXT_LIMIT: 10,
  AVAILABLE_AGENTS_CONTEXT_QUERY_LIMIT: 12,
  agentService: {
    queryAgents: vi.fn(),
  },
}));

// 默认设置运行环境为 browser/client
const runtimeFlags = vi.hoisted(() => ({
  isServerMode: false,
}));

vi.mock('@lobechat/const', async (importOriginal) => {
  const actual = await importOriginal();
  return {
    ...(actual as any),
    get isServerMode() {
      return runtimeFlags.isServerMode;
    },
    isDesktop: false,
    isDeprecatedEdition: false,
  };
});

beforeEach(() => {
  vi.mocked(agentService.queryAgents).mockResolvedValue([]);
  useAgentStore.setState({
    agentMap: {},
    availableAgents: undefined,
  });
});

afterEach(() => {
  runtimeFlags.isServerMode = false;
  vi.resetModules();
  vi.clearAllMocks();
});

// Helper to compute expected date content from SystemDateProvider
const getCurrentDateContent = () => {
  const tz = 'UTC';
  const today = new Date();
  const year = today.toLocaleString('en-US', { timeZone: tz, year: 'numeric' });
  const month = today.toLocaleString('en-US', { month: '2-digit', timeZone: tz });
  const day = today.toLocaleString('en-US', { day: '2-digit', timeZone: tz });
  return `Current date: ${year}-${month}-${day} (${tz})`;
};

describe('contextEngineering', () => {
  it('should not fetch agent documents implicitly when agentId is provided', async () => {
    const messages = [{ content: 'Hello', role: 'user' }] as UIChatMessage[];

    await contextEngineering({
      agentId: 'agent-1',
      messages,
      model: 'gpt-4',
      provider: 'openai',
    });

    expect(agentDocumentService.getDocuments).not.toHaveBeenCalled();
  });

  it('should use provided agent documents without fetching', async () => {
    const messages = [{ content: 'Summarize the setup', role: 'user' }] as UIChatMessage[];

    const output = await contextEngineering({
      agentDocuments: [
        {
          content: 'Project setup steps',
          filename: 'setup.md',
          id: 'doc-1',
          // `always` keeps this doc in the inline bucket; without it the
          // default is progressive (metadata-only index, content hidden).
          policyLoad: 'always',
          title: 'Setup',
        },
      ],
      agentId: 'agent-1',
      messages,
      model: 'gpt-4',
      provider: 'openai',
    });

    expect(agentDocumentService.getDocuments).not.toHaveBeenCalled();
    const documentsMessage = output.find(
      (message) =>
        message.role === 'user' &&
        typeof message.content === 'string' &&
        message.content.includes('Project setup steps'),
    );

    expect(documentsMessage).toEqual({
      content: expect.stringContaining('Project setup steps'),
      role: 'user',
    });
  });

  it('should use cached available agents without querying during context engineering', async () => {
    useAgentStore.setState({
      availableAgents: [
        {
          avatar: null,
          backgroundColor: null,
          description: null,
          id: 'agent-1',
          title: 'Current Agent',
        },
        {
          avatar: null,
          backgroundColor: null,
          description: 'Helps with setup',
          id: 'agent-2',
          title: 'Setup Agent',
        },
      ],
    });

    await contextEngineering({
      agentId: 'agent-1',
      messages: [{ content: 'Hello', role: 'user' }] as UIChatMessage[],
      model: 'gpt-4',
      provider: 'openai',
    });

    expect(agentService.queryAgents).not.toHaveBeenCalled();
  });

  it('should query available agents when the prefetch cache is missing', async () => {
    await contextEngineering({
      agentId: 'agent-1',
      messages: [{ content: 'Hello', role: 'user' }] as UIChatMessage[],
      model: 'gpt-4',
      provider: 'openai',
    });

    expect(agentService.queryAgents).toHaveBeenCalledWith({ limit: 12 });
  });

  describe('handle with files content in server mode', () => {
    it('should includes files', async () => {
      runtimeFlags.isServerMode = true;
      // Mock isCanUseVision to return true for vision models
      vi.spyOn(helpers, 'isCanUseVision').mockReturnValue(true);

      const messages = [
        {
          content: 'Hello',
          role: 'user',
          imageList: [
            {
              id: 'imagecx1',
              url: 'http://example.com/xxx0asd-dsd.png',
              alt: 'ttt.png',
            },
          ],
          fileList: [
            {
              fileType: 'plain/txt',
              size: 100000,
              id: 'file1',
              url: 'http://abc.com/abc.txt',
              name: 'abc.png',
            },
            {
              id: 'file_oKMve9qySLMI',
              name: '2402.16667v1.pdf',
              type: 'application/pdf',
              size: 11256078,
              url: 'https://xxx.com/ppp/480497/5826c2b8-fde0-4de1-a54b-a224d5e3d898.pdf',
            },
          ],
        }, // Message with files
        { content: 'Hey', role: 'assistant' }, // Regular user message
      ] as UIChatMessage[];

      const output = await contextEngineering({
        messages,
        model: 'gpt-4o',
        provider: 'openai',
      });

      expect(output).toEqual([
        { content: expect.stringContaining(getCurrentDateContent()), role: 'system' },
        {
          content: [
            {
              text: `Hello

<!-- SYSTEM CONTEXT (NOT PART OF USER QUERY) -->
<context.instruction>following part contains context information injected by the system. Please follow these instructions:

1. Always prioritize handling user-visible content.
2. the context is only required when user's queries rely on it.
</context.instruction>
<files_info>
<images>
<images_docstring>here are user upload images you can refer to</images_docstring>
<image ref="image_1" name="ttt.png" url="http://example.com/xxx0asd-dsd.png"></image>
</images>
<files>
<files_docstring>here are user upload files you can refer to</files_docstring>
<file id="file1" name="abc.png" type="plain/txt" size="100000" url="http://abc.com/abc.txt"></file>
<file id="file_oKMve9qySLMI" name="2402.16667v1.pdf" type="undefined" size="11256078" url="https://xxx.com/ppp/480497/5826c2b8-fde0-4de1-a54b-a224d5e3d898.pdf"></file>
</files>
</files_info>
<!-- END SYSTEM CONTEXT -->`,
              type: 'text',
            },
            {
              image_url: { detail: 'auto', url: 'http://example.com/xxx0asd-dsd.png' },
              type: 'image_url',
            },
          ],
          role: 'user',
        },
        {
          content: 'Hey',
          role: 'assistant',
        },
      ]);

      runtimeFlags.isServerMode = false;
    });

    it('should include image files in server mode', async () => {
      runtimeFlags.isServerMode = true;

      vi.spyOn(helpers, 'isCanUseVision').mockReturnValue(false);

      const messages = [
        {
          content: 'Hello',
          role: 'user',
          imageList: [
            {
              id: 'file1',
              url: 'http://example.com/image.jpg',
              alt: 'abc.png',
            },
          ],
        }, // Message with files
        { content: 'Hey', role: 'assistant' }, // Regular user message
      ] as UIChatMessage[];
      const output = await contextEngineering({
        messages,
        provider: 'openai',
        model: 'gpt-4-vision-preview',
      });

      expect(output).toEqual([
        { content: expect.stringContaining(getCurrentDateContent()), role: 'system' },
        {
          content: [
            {
              // Vision disabled: the image is surfaced in the file-context
              // block AND appended as a textual placeholder so the target
              // model still sees that an image was sent (see ).
              text: `Hello

[image omitted: not supported by this model]

<!-- SYSTEM CONTEXT (NOT PART OF USER QUERY) -->
<context.instruction>following part contains context information injected by the system. Please follow these instructions:

1. Always prioritize handling user-visible content.
2. the context is only required when user's queries rely on it.
</context.instruction>
<files_info>
<images>
<images_docstring>here are user upload images you can refer to</images_docstring>
<image ref="image_1" name="abc.png" url="http://example.com/image.jpg"></image>
</images>
</files_info>
<!-- END SYSTEM CONTEXT -->`,
              type: 'text',
            },
          ],
          role: 'user',
        },
        {
          content: 'Hey',
          role: 'assistant',
        },
      ]);

      runtimeFlags.isServerMode = false;
    });
  });

  it('should handle empty tool calls messages correctly', async () => {
    const messages = [
      {
        content: '## Tools\n\nYou can use these tools',
        role: 'system',
      },
      {
        content: '',
        role: 'assistant',
        tool_calls: [],
      },
    ] as UIChatMessage[];

    const result = await contextEngineering({
      messages,
      model: 'gpt-4',
      provider: 'openai',
    });

    expect(result).toEqual([
      {
        content: expect.stringContaining(
          '## Tools\n\nYou can use these tools\n\n' + getCurrentDateContent(),
        ),
        role: 'system',
      },
      {
        content: '',
        role: 'assistant',
      },
    ]);
  });

  it('should handle assistant messages with reasoning correctly', async () => {
    const messages = [
      {
        role: 'assistant',
        content: 'The answer is 42.',
        reasoning: {
          content: 'I need to calculate the answer to life, universe, and everything.',
          signature: 'thinking_process',
        },
      },
    ] as UIChatMessage[];

    const result = await contextEngineering({
      messages,
      model: 'gpt-4',
      provider: 'openai',
    });

    expect(result).toEqual([
      { content: expect.stringContaining(getCurrentDateContent()), role: 'system' },
      {
        content: [
          {
            signature: 'thinking_process',
            thinking: 'I need to calculate the answer to life, universe, and everything.',
            type: 'thinking',
          },
          {
            text: 'The answer is 42.',
            type: 'text',
          },
        ],
        reasoning: {
          content: 'I need to calculate the answer to life, universe, and everything.',
          signature: 'thinking_process',
        },
        role: 'assistant',
      },
    ]);
  });

  it('should inject historySummary into system message when provided', async () => {
    const historySummary = 'Previous conversation summary: User discussed AI topics.';

    const messages: UIChatMessage[] = [
      {
        role: 'user',
        content: 'Continue our discussion',
        createdAt: Date.now(),
        id: 'test-history',
        updatedAt: Date.now(),
      },
    ];

    const result = await contextEngineering({
      messages,
      model: 'gpt-4',
      historySummary,
      provider: 'openai',
    });

    // Should have system message with history summary
    const systemMessage = result.find((msg) => msg.role === 'system');
    expect(systemMessage).toBeDefined();
    expect(systemMessage!.content).toContain(historySummary);
    expect(Object.keys(systemMessage!).length).toEqual(2);
  });

  it('should preserve normalized skill and tool tags in user messages before sending to model', async () => {
    vi.spyOn(isCanUseFCModule, 'isCanUseFC').mockReturnValue(true);

    const messages: UIChatMessage[] = [
      {
        role: 'user',
        content:
          '<skill name="grep" label="Grep" /> <tool name="lobe-notebook" label="Notebook" /> hi',
        createdAt: Date.now(),
        id: 'selected-skill-user',
        updatedAt: Date.now(),
      },
    ];

    const result = await contextEngineering({
      messages,
      model: 'gpt-4',
      provider: 'openai',
    });

    expect(result[0]).toEqual({
      content: expect.stringContaining(getCurrentDateContent()),
      role: 'system',
    });
    expect(result[1].role).toBe('user');
    expect(result[1].content).toContain('hi');
    expect(result[1].content).toContain('<skill name="grep" label="Grep" />');
    expect(result[1].content).toContain('<tool name="lobe-notebook" label="Notebook" />');
  });

  describe('getAssistantContent', () => {
    it('should handle assistant message with imageList and content', async () => {
      // Mock isCanUseVision to return true for vision models
      vi.spyOn(helpers, 'isCanUseVision').mockReturnValue(true);

      const messages: UIChatMessage[] = [
        {
          role: 'assistant',
          content: 'Here is an image.',
          imageList: [{ id: 'img1', url: 'http://example.com/image.png', alt: 'test.png' }],
          createdAt: Date.now(),
          id: 'test-id',
          updatedAt: Date.now(),
        },
      ];
      const result = await contextEngineering({
        messages,
        model: 'gpt-4-vision-preview',
        provider: 'openai',
      });

      expect(result[0]).toEqual({
        content: expect.stringContaining(getCurrentDateContent()),
        role: 'system',
      });
      expect(result[1].content).toEqual([
        { text: 'Here is an image.', type: 'text' },
        { image_url: { detail: 'auto', url: 'http://example.com/image.png' }, type: 'image_url' },
      ]);
    });

    it('should handle assistant message with imageList but no content', async () => {
      // Mock isCanUseVision to return true for vision models
      vi.spyOn(helpers, 'isCanUseVision').mockReturnValue(true);

      const messages: UIChatMessage[] = [
        {
          role: 'assistant',
          content: '',
          imageList: [{ id: 'img1', url: 'http://example.com/image.png', alt: 'test.png' }],
          createdAt: Date.now(),
          id: 'test-id-2',
          updatedAt: Date.now(),
        },
      ];
      const result = await contextEngineering({
        messages,
        model: 'gpt-4-vision-preview',
        provider: 'openai',
      });

      expect(result[0]).toEqual({
        content: expect.stringContaining(getCurrentDateContent()),
        role: 'system',
      });
      expect(result[1].content).toEqual([
        { image_url: { detail: 'auto', url: 'http://example.com/image.png' }, type: 'image_url' },
      ]);
    });
  });

  it('should not include tool_calls for assistant message if model does not support tools', async () => {
    // Mock isCanUseFC to return false
    vi.spyOn(isCanUseFCModule, 'isCanUseFC').mockReturnValue(false);

    const messages: UIChatMessage[] = [
      {
        role: 'assistant',
        content: 'I have a tool call.',
        tools: [
          {
            id: 'tool_123',
            type: 'default',
            apiName: 'testApi',
            arguments: '{}',
            identifier: 'test-plugin',
          },
        ],
        createdAt: Date.now(),
        id: 'test-id-3',
        updatedAt: Date.now(),
      },
    ];

    const result = await contextEngineering({
      messages,
      model: 'some-model-without-fc',
      provider: 'openai',
    });

    expect(result[0]).toEqual({
      content: expect.stringContaining(getCurrentDateContent()),
      role: 'system',
    });
    expect(result[1].tool_calls).toBeUndefined();
    expect(result[1].content).toBe('I have a tool call.');
  });

  describe('Process placeholder variables', () => {
    it('should process placeholder variables in string content', async () => {
      const messages: UIChatMessage[] = [
        {
          role: 'user',
          content: 'Hello {{username}}, today is {{date}} and the time is {{time}}',
          createdAt: Date.now(),
          id: 'test-placeholder-1',
          updatedAt: Date.now(),
        },
        {
          role: 'assistant',
          content: 'Hi there! Your random number is {{random}}',
          createdAt: Date.now(),
          id: 'test-placeholder-2',
          updatedAt: Date.now(),
        },
      ];

      const result = await contextEngineering({
        messages,
        model: 'gpt-4',
        provider: 'openai',
      });

      expect(result[0]).toEqual({
        content: expect.stringContaining(getCurrentDateContent()),
        role: 'system',
      });
      expect(result[1].content).toBe(
        'Hello TestUser, today is 2023-12-25 and the time is 14:30:45',
      );
      expect(result[2].content).toBe('Hi there! Your random number is 12345');
    });

    it('should process placeholder variables in array content', async () => {
      const messages = [
        {
          role: 'user',
          content: [
            {
              type: 'text',
              text: 'Hello {{username}}, today is {{date}}',
            },
            {
              type: 'image_url',
              image_url: { url: 'data:image/png;base64,abc123' },
            },
          ],
          createdAt: Date.now(),
          id: 'test-placeholder-array',
          updatedAt: Date.now(),
        },
      ] as any;

      const result = await contextEngineering({
        messages,
        model: 'gpt-4',
        provider: 'openai',
      });

      expect(result[0]).toEqual({
        content: expect.stringContaining(getCurrentDateContent()),
        role: 'system',
      });
      expect(Array.isArray(result[1].content)).toBe(true);
      const content = result[1].content as any[];
      expect(content[0].text).toBe('Hello TestUser, today is 2023-12-25');
      expect(content[1].image_url.url).toBe('data:image/png;base64,abc123');
    });

    it('should merge custom memory placeholder variables', async () => {
      const messages: UIChatMessage[] = [
        {
          role: 'system',
          content:
            'Memory load: available={{memory_available}}, total contexts={{memory_contexts_count}}\n{{memory_summary}}',
          createdAt: Date.now(),
          id: 'memory-placeholder-test',
          updatedAt: Date.now(),
        },
        {
          role: 'user',
          content: 'Hello',
          createdAt: Date.now(),
          id: 'memory-placeholder-user',
          updatedAt: Date.now(),
        },
      ];

      // Mock topic memories and user persona separately
      vi.spyOn(memoryManager, 'resolveTopicMemories').mockReturnValue({
        activities: [],
        contexts: [
          {
            accessedAt: new Date('2024-01-01T00:00:00.000Z'),
            associatedObjects: [],
            associatedSubjects: [],
            createdAt: new Date('2024-01-01T00:00:00.000Z'),
            currentStatus: 'active',
            description: 'Weekly syncs for LobeHub',
            id: 'ctx-1',
            metadata: {},
            scoreImpact: 0.8,
            scoreUrgency: 0.5,
            tags: ['project'],
            title: 'LobeHub',
            type: 'project',
            updatedAt: new Date('2024-01-02T00:00:00.000Z'),
            userMemoryIds: ['mem-1'],
          },
        ],
        experiences: [],
        preferences: [],
      });
      vi.spyOn(memoryManager, 'resolveUserPersona').mockReturnValue(undefined);

      const result = await contextEngineering({
        enableUserMemories: true,
        messages,
        model: 'gpt-4',
        provider: 'openai',
      });

      // Keep the original system message as-is (with date appended by SystemDateProvider)
      expect(result[0].role).toBe('system');
      expect(result[0].content).toContain(
        'Memory load: available={{memory_available}}, total contexts={{memory_contexts_count}}\n{{memory_summary}}\n\n' +
          getCurrentDateContent(),
      );

      // Memory context is injected as a consolidated user message before the first user message
      // Note: meta/id fields are removed by the engine cleanup step, so assert via content.
      const injection = result.find(
        (m: any) => m.role === 'user' && String(m.content).includes('<user_memory>'),
      );
      expect(injection).toBeDefined();
      expect(injection!.role).toBe('user');
      expect(injection!.content).toContain('<user_memory>');
      expect(injection!.content).toContain('<contexts count="1">');
      expect(injection!.content).toContain('<context id="ctx-1" title="LobeHub">');
    });

    it('should handle missing placeholder variables gracefully', async () => {
      const messages: UIChatMessage[] = [
        {
          role: 'user',
          content: 'Hello {{username}}, missing: {{missing_var}}',
          createdAt: Date.now(),
          id: 'test-placeholder-missing',
          updatedAt: Date.now(),
        },
      ];

      const result = await contextEngineering({
        messages,
        model: 'gpt-4',
        provider: 'openai',
      });

      expect(result[0]).toEqual({
        content: expect.stringContaining(getCurrentDateContent()),
        role: 'system',
      });
      expect(result[1].content).toBe('Hello TestUser, missing: {{missing_var}}');
    });

    it('should not modify messages without placeholder variables', async () => {
      const messages: UIChatMessage[] = [
        {
          role: 'user',
          content: 'Hello there, no variables here',
          createdAt: Date.now(),
          id: 'test-no-placeholders',
          updatedAt: Date.now(),
        },
      ];

      const result = await contextEngineering({
        messages,
        model: 'gpt-4',
        provider: 'openai',
      });

      expect(result[0]).toEqual({
        content: expect.stringContaining(getCurrentDateContent()),
        role: 'system',
      });
      expect(result[1].content).toBe('Hello there, no variables here');
    });

    it('should process placeholder variables combined with other processors', async () => {
      runtimeFlags.isServerMode = true;
      vi.spyOn(helpers, 'isCanUseVision').mockReturnValue(true);

      const messages: UIChatMessage[] = [
        {
          role: 'user',
          content: 'Hello {{username}}, check this image from {{date}}',
          imageList: [
            {
              id: 'img1',
              url: 'http://example.com/test.jpg',
              alt: 'test image',
            },
          ],
          createdAt: Date.now(),
          id: 'test-combined',
          updatedAt: Date.now(),
        },
      ];

      const result = await contextEngineering({
        messages,
        model: 'gpt-4o',
        provider: 'openai',
      });

      expect(result[0]).toEqual({
        content: expect.stringContaining(getCurrentDateContent()),
        role: 'system',
      });
      expect(Array.isArray(result[1].content)).toBe(true);
      const content = result[1].content as any[];

      // Should contain processed placeholder variables in the text content
      expect(content[0].text).toContain('Hello TestUser, check this image from 2023-12-25');

      // Should also contain file context from MessageContentProcessor
      expect(content[0].text).toContain('SYSTEM CONTEXT');

      // Should contain image from vision processing
      expect(content[1].type).toBe('image_url');
      expect(content[1].image_url.url).toBe('http://example.com/test.jpg');

      runtimeFlags.isServerMode = false;
    });
  });

  describe('Message preprocessing processors', () => {
    it('should keep all messages (no history truncation)', async () => {
      const messages: UIChatMessage[] = [
        {
          role: 'user',
          content: 'Message 1',
          createdAt: Date.now(),
          id: 'test-1',
          updatedAt: Date.now(),
        },
        {
          role: 'assistant',
          content: 'Response 1',
          createdAt: Date.now(),
          id: 'test-2',
          updatedAt: Date.now(),
        },
        {
          role: 'user',
          content: 'Message 2',
          createdAt: Date.now(),
          id: 'test-3',
          updatedAt: Date.now(),
        },
        {
          role: 'assistant',
          content: 'Response 2',
          createdAt: Date.now(),
          id: 'test-4',
          updatedAt: Date.now(),
        },
        {
          role: 'user',
          content: 'Latest message',
          createdAt: Date.now(),
          id: 'test-5',
          updatedAt: Date.now(),
        },
      ];

      const result = await contextEngineering({
        messages,
        model: 'gpt-4',
        provider: 'openai',
      });

      // Should keep all messages (plus system date)
      expect(result).toHaveLength(6);
      expect(result).toEqual([
        { content: expect.stringContaining(getCurrentDateContent()), role: 'system' },
        { content: 'Message 1', role: 'user' },
        { content: 'Response 1', role: 'assistant' },
        { content: 'Message 2', role: 'user' },
        { content: 'Response 2', role: 'assistant' },
        { content: 'Latest message', role: 'user' },
      ]);
    });

    it('should apply input template to user messages', async () => {
      const messages: UIChatMessage[] = [
        {
          role: 'user',
          content: 'Original user input',
          createdAt: Date.now(),
          id: 'test-template',
          updatedAt: Date.now(),
        },
        {
          role: 'assistant',
          content: 'Assistant response',
          createdAt: Date.now(),
          id: 'test-assistant',
          updatedAt: Date.now(),
        },
      ];

      const result = await contextEngineering({
        messages,
        model: 'gpt-4',
        provider: 'openai',
        inputTemplate: 'Template: {{text}} - End',
      });

      // Should apply template to user message only
      expect(result).toEqual([
        { content: expect.stringContaining(getCurrentDateContent()), role: 'system' },
        {
          content: 'Template: Original user input - End',
          role: 'user',
        },
        {
          role: 'assistant',
          content: 'Assistant response',
        },
      ]);
      expect(result[2].content).toBe('Assistant response'); // Unchanged
    });

    it('should inject system role at the beginning', async () => {
      const messages: UIChatMessage[] = [
        {
          role: 'user',
          content: 'User message',
          createdAt: Date.now(),
          id: 'test-user',
          updatedAt: Date.now(),
        },
      ];

      const result = await contextEngineering({
        messages,
        model: 'gpt-4',
        provider: 'openai',
        systemRole: 'You are a helpful assistant.',
      });

      // Should have system role at the beginning (with date appended)
      expect(result).toEqual([
        {
          content: expect.stringContaining(
            'You are a helpful assistant.\n\n' + getCurrentDateContent(),
          ),
          role: 'system',
        },
        { content: 'User message', role: 'user' },
      ]);
    });

    it('should combine system role and input template correctly', async () => {
      const messages: UIChatMessage[] = [
        {
          role: 'user',
          content: 'Old message 1',
          createdAt: Date.now(),
          id: 'test-old-1',
          updatedAt: Date.now(),
        },
        {
          role: 'assistant',
          content: 'Old response',
          createdAt: Date.now(),
          id: 'test-old-2',
          updatedAt: Date.now(),
        },
        {
          role: 'user',
          content: 'Recent input with {{username}}',
          createdAt: Date.now(),
          id: 'test-recent',
          updatedAt: Date.now(),
        },
      ];

      const result = await contextEngineering({
        messages,
        model: 'gpt-4',
        provider: 'openai',
        systemRole: 'System instructions.',
        inputTemplate: 'Processed: {{text}}',
      });

      // System role should be first (with date appended), followed by all messages with input template applied to user messages
      expect(result).toEqual([
        {
          content: expect.stringContaining('System instructions.\n\n' + getCurrentDateContent()),
          role: 'system',
        },
        {
          content: 'Processed: Old message 1',
          role: 'user',
        },
        {
          role: 'assistant',
          content: 'Old response',
        },
        {
          content: 'Processed: Recent input with TestUser',
          role: 'user',
        },
      ]);
    });

    it('should skip preprocessing when no configuration is provided', async () => {
      const messages: UIChatMessage[] = [
        {
          role: 'user',
          content: 'Simple message',
          createdAt: Date.now(),
          id: 'test-simple',
          updatedAt: Date.now(),
        },
      ];

      const result = await contextEngineering({
        messages,
        model: 'gpt-4',
        provider: 'openai',
      });

      // Should pass message unchanged (with system date prepended)
      expect(result).toEqual([
        { content: expect.stringContaining(getCurrentDateContent()), role: 'system' },
        {
          content: 'Simple message',
          role: 'user',
        },
      ]);
    });

    it('should handle system role injection with all messages (no history truncation)', async () => {
      const messages: UIChatMessage[] = [
        {
          role: 'user',
          content: 'Message 1',
          createdAt: Date.now(),
          id: 'test-1',
          updatedAt: Date.now(),
        },
        {
          role: 'user',
          content: 'Message 2',
          createdAt: Date.now(),
          id: 'test-2',
          updatedAt: Date.now(),
        },
        {
          role: 'user',
          content: 'Message 3',
          createdAt: Date.now(),
          id: 'test-3',
          updatedAt: Date.now(),
        },
      ];

      const result = await contextEngineering({
        messages,
        model: 'gpt-4',
        provider: 'openai',
        systemRole: 'System role here.',
      });

      // Should have system role (with date) + all messages
      expect(result).toEqual([
        {
          content: expect.stringContaining('System role here.\n\n' + getCurrentDateContent()),
          role: 'system',
        },
        {
          content: 'Message 1',
          role: 'user',
        },
        {
          content: 'Message 2',
          role: 'user',
        },
        {
          content: 'Message 3',
          role: 'user',
        },
      ]);
    });

    it('should handle input template compilation errors gracefully', async () => {
      const messages: UIChatMessage[] = [
        {
          role: 'user',
          content: 'User message',
          createdAt: Date.now(),
          id: 'test-error',
          updatedAt: Date.now(),
        },
      ];

      // This should not throw an error, but handle it gracefully
      const result = await contextEngineering({
        messages,
        model: 'gpt-4',
        provider: 'openai',
        inputTemplate: '<%- invalid javascript syntax %>',
      });

      // Should keep original message when template fails (with system date prepended)
      expect(result).toEqual([
        { content: expect.stringContaining(getCurrentDateContent()), role: 'system' },
        {
          content: 'User message',
          role: 'user',
        },
      ]);
    });
  });
});
