/**
 * Tests for XML Encoding Workaround
 *
 * When calling MCP tools via XML-based clients (like Claude Code), the >> prefix
 * gets HTML-decoded, causing >> to become >. This test suite validates that
 * symbolic operators provide a workaround by making the >> prefix optional.
 */

import { describe, expect, test, beforeEach } from '@jest/globals';

import { createUnifiedCommandParser } from '../../../../src/engine/execution/parsers/index.js';
import { MockLogger } from '../../../helpers/test-helpers.js';

import type { ConvertedPrompt } from '../../../../src/shared/types/index.js';

describe('XML Encoding Workaround - Symbolic Operators Without >> Prefix', () => {
  let parser: ReturnType<typeof createUnifiedCommandParser>;
  let mockPrompts: ConvertedPrompt[];

  beforeEach(() => {
    const logger = new MockLogger();
    parser = createUnifiedCommandParser(logger);

    mockPrompts = [
      {
        id: 'test_prompt',
        name: 'Test Prompt',
        userMessageTemplate: 'Test template',
        description: 'Test prompt',
        category: 'test',
        arguments: [],
      },
      {
        id: 'test_simple',
        name: 'Simple Test',
        userMessageTemplate: 'Simple template',
        description: 'Simple test prompt',
        category: 'test',
        arguments: [],
      },
    ];
  });

  describe('Chain Operator (-->) makes >> prefix optional', () => {
    test('parses chain command without >> prefix', async () => {
      const result = await parser.parseCommand(
        'test_prompt input="value1" --> test_simple input="value2"',
        mockPrompts
      );

      expect(result).toBeDefined();
      expect(result.promptId).toBe('test_prompt');
      expect(result.format).toBe('symbolic');
      expect(result.commandType).toBe('chain');
      expect(result.operators?.operatorTypes).toContain('chain');
    });

    test('also accepts chain command WITH >> prefix', async () => {
      const result = await parser.parseCommand(
        '>>test_prompt input="value1" --> test_simple input="value2"',
        mockPrompts
      );

      expect(result).toBeDefined();
      expect(result.promptId).toBe('test_prompt');
      expect(result.commandType).toBe('chain');
    });

    test('parses multi-step chain without >> prefix', async () => {
      const result = await parser.parseCommand(
        'test_prompt --> test_simple --> test_prompt',
        mockPrompts
      );

      expect(result).toBeDefined();
      expect(result.commandType).toBe('chain');
      expect(result.operators?.operatorTypes).toContain('chain');
    });
  });

  describe('Framework Operator (@) makes >> prefix optional', () => {
    test('parses framework command without >> prefix', async () => {
      const result = await parser.parseCommand('@CAGEERF test_prompt input="value"', mockPrompts);

      expect(result).toBeDefined();
      expect(result.promptId).toBe('test_prompt');
      expect(result.format).toBe('symbolic');
      expect(result.operators?.operatorTypes).toContain('framework');
    });

    test('also accepts framework command WITH >> prefix', async () => {
      const result = await parser.parseCommand('@CAGEERF >>test_prompt input="value"', mockPrompts);

      expect(result).toBeDefined();
      expect(result.promptId).toBe('test_prompt');
    });
  });

  describe('Gate Operator (::) makes >> prefix optional', () => {
    test('parses gate command without >> prefix', async () => {
      const result = await parser.parseCommand(
        'test_prompt input="value" :: "quality check"',
        mockPrompts
      );

      expect(result).toBeDefined();
      expect(result.promptId).toBe('test_prompt');
      expect(result.format).toBe('symbolic');
      expect(result.operators?.operatorTypes).toContain('gate');
    });

    test('also accepts gate command WITH >> prefix', async () => {
      const result = await parser.parseCommand(
        '>>test_prompt input="value" :: "quality check"',
        mockPrompts
      );

      expect(result).toBeDefined();
      expect(result.promptId).toBe('test_prompt');
    });
  });

  describe('Combined Operators work without >> prefix', () => {
    test('framework + chain operators', async () => {
      const result = await parser.parseCommand('@CAGEERF test_prompt --> test_simple', mockPrompts);

      expect(result).toBeDefined();
      expect(result.promptId).toBe('test_prompt');
      expect(result.operators?.operatorTypes).toContain('framework');
      expect(result.operators?.operatorTypes).toContain('chain');
    });

    test('chain + gate operators', async () => {
      const result = await parser.parseCommand(
        'test_prompt --> test_simple :: "quality"',
        mockPrompts
      );

      expect(result).toBeDefined();
      expect(result.promptId).toBe('test_prompt');
      expect(result.operators?.operatorTypes).toContain('chain');
      expect(result.operators?.operatorTypes).toContain('gate');
    });
  });

  describe('Error cases', () => {
    test('single > prefix (from >> being stripped) provides XML encoding warning', async () => {
      await expect(parser.parseCommand('>test_prompt input="value"', mockPrompts)).rejects.toThrow(
        /Single ">" detected.*XML encoding/
      );
    });
  });

  describe('Bare prompt name support', () => {
    test('bare prompt name without >> prefix is now accepted', async () => {
      const result = await parser.parseCommand('test_prompt input="value"', mockPrompts);
      expect(result.promptId).toBe('test_prompt');
      expect(result.format).toBe('simple');
      expect(result.metadata?.detectedFormat).toBe('bare prompt name');
    });
  });
});
