/**
 * Integration tests for ToolSanitizationProxy
 *
 * Tests the full proxy flow: request sanitization → upstream forwarding → response restoration
 */

import { describe, it, expect, beforeAll, afterAll, beforeEach } from 'bun:test';
import * as http from 'http';
import { ToolSanitizationProxy } from '../../../src/cliproxy/tool-sanitization-proxy';

// Mock upstream server that echoes requests
let mockUpstream: http.Server;
let mockUpstreamPort: number;
let lastRequest: { body: unknown; headers: http.IncomingHttpHeaders } | null = null;

// Track response to send back
let mockResponse: { status: number; body: unknown; stream?: boolean } = {
  status: 200,
  body: { content: [] },
};

beforeAll(async () => {
  await new Promise<void>((resolve) => {
    mockUpstream = http.createServer((req, res) => {
      const chunks: Buffer[] = [];

      req.on('data', (chunk) => chunks.push(chunk));
      req.on('end', () => {
        const body = Buffer.concat(chunks).toString('utf8');
        lastRequest = {
          body: body ? JSON.parse(body) : null,
          headers: req.headers,
        };

        if (mockResponse.stream) {
          // SSE streaming response
          res.writeHead(mockResponse.status, {
            'Content-Type': 'text/event-stream',
            'Cache-Control': 'no-cache',
            Connection: 'keep-alive',
          });
          const events = mockResponse.body as string[];
          for (const event of events) {
            res.write(event);
          }
          res.end();
        } else {
          // Buffered JSON response
          res.writeHead(mockResponse.status, { 'Content-Type': 'application/json' });
          res.end(JSON.stringify(mockResponse.body));
        }
      });
    });

    mockUpstream.listen(0, '127.0.0.1', () => {
      const addr = mockUpstream.address();
      mockUpstreamPort = typeof addr === 'object' && addr ? addr.port : 0;
      resolve();
    });
  });
});

afterAll(() => {
  mockUpstream?.close();
});

beforeEach(() => {
  lastRequest = null;
  mockResponse = { status: 200, body: { content: [] } };
});

describe('ToolSanitizationProxy Integration', () => {
  describe('Proxy Lifecycle', () => {
    it('starts on ephemeral port and stops cleanly', async () => {
      const proxy = new ToolSanitizationProxy({
        upstreamBaseUrl: `http://127.0.0.1:${mockUpstreamPort}`,
      });

      const port = await proxy.start();
      expect(port).toBeGreaterThan(0);
      expect(proxy.getPort()).toBe(port);

      proxy.stop();
      expect(proxy.getPort()).toBeNull();
    });

    it('returns same port on multiple start calls', async () => {
      const proxy = new ToolSanitizationProxy({
        upstreamBaseUrl: `http://127.0.0.1:${mockUpstreamPort}`,
      });

      const port1 = await proxy.start();
      const port2 = await proxy.start();
      expect(port1).toBe(port2);

      proxy.stop();
    });
  });

  describe('Request Sanitization', () => {
    it('sanitizes duplicate segment tool names in request', async () => {
      const proxy = new ToolSanitizationProxy({
        upstreamBaseUrl: `http://127.0.0.1:${mockUpstreamPort}`,
      });
      const port = await proxy.start();

      try {
        const response = await fetch(`http://127.0.0.1:${port}/v1/messages`, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            model: 'test-model',
            tools: [
              {
                name: 'gitmcp__plus-pro-components__plus-pro-components',
                description: 'Test tool',
              },
              { name: 'valid_tool', description: 'Valid tool' },
            ],
            messages: [{ role: 'user', content: 'test' }],
          }),
        });

        expect(response.ok).toBe(true);
        expect(lastRequest).not.toBeNull();

        const sentTools = (lastRequest!.body as Record<string, unknown>).tools as Array<{
          name: string;
        }>;
        expect(sentTools[0].name).toBe('gitmcp__plus-pro-components');
        expect(sentTools[1].name).toBe('valid_tool');
      } finally {
        proxy.stop();
      }
    });

    it('truncates tool names exceeding 64 characters', async () => {
      const proxy = new ToolSanitizationProxy({
        upstreamBaseUrl: `http://127.0.0.1:${mockUpstreamPort}`,
      });
      const port = await proxy.start();

      try {
        const longName = 'a'.repeat(100);
        await fetch(`http://127.0.0.1:${port}/v1/messages`, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            tools: [{ name: longName }],
          }),
        });

        const sentTools = (lastRequest!.body as Record<string, unknown>).tools as Array<{
          name: string;
        }>;
        expect(sentTools[0].name.length).toBe(64);
        expect(sentTools[0].name).toContain('_'); // Has hash separator
      } finally {
        proxy.stop();
      }
    });

    it('passes through requests without tools unchanged', async () => {
      const proxy = new ToolSanitizationProxy({
        upstreamBaseUrl: `http://127.0.0.1:${mockUpstreamPort}`,
      });
      const port = await proxy.start();

      try {
        const originalBody = {
          model: 'test-model',
          messages: [{ role: 'user', content: 'Hello' }],
        };

        await fetch(`http://127.0.0.1:${port}/v1/messages`, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify(originalBody),
        });

        expect(lastRequest!.body).toEqual(originalBody);
      } finally {
        proxy.stop();
      }
    });

    it('normalizes dotted Claude thinking model IDs for root/composite routes', async () => {
      const proxy = new ToolSanitizationProxy({
        upstreamBaseUrl: `http://127.0.0.1:${mockUpstreamPort}`,
      });
      const port = await proxy.start();

      try {
        await fetch(`http://127.0.0.1:${port}/v1/messages`, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            model: 'claude-sonnet-4.6-thinking',
            messages: [{ role: 'user', content: 'test' }],
          }),
        });

        expect(lastRequest).not.toBeNull();
        expect((lastRequest!.body as Record<string, unknown>).model).toBe('claude-sonnet-4-6');
      } finally {
        proxy.stop();
      }
    });

    it('keeps dotted non-thinking model IDs unchanged', async () => {
      const proxy = new ToolSanitizationProxy({
        upstreamBaseUrl: `http://127.0.0.1:${mockUpstreamPort}`,
      });
      const port = await proxy.start();

      try {
        await fetch(`http://127.0.0.1:${port}/v1/messages`, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            model: 'claude-sonnet-4.5',
            messages: [{ role: 'user', content: 'test' }],
          }),
        });

        expect(lastRequest).not.toBeNull();
        expect((lastRequest!.body as Record<string, unknown>).model).toBe('claude-sonnet-4.5');
      } finally {
        proxy.stop();
      }
    });

    it('normalizes dotted Claude major.minor IDs on antigravity provider route', async () => {
      const proxy = new ToolSanitizationProxy({
        upstreamBaseUrl: `http://127.0.0.1:${mockUpstreamPort}`,
      });
      const port = await proxy.start();

      try {
        await fetch(`http://127.0.0.1:${port}/api/provider/agy/v1/messages`, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            model: 'claude-opus-4.6',
            messages: [{ role: 'user', content: 'test' }],
          }),
        });

        expect(lastRequest).not.toBeNull();
        expect((lastRequest!.body as Record<string, unknown>).model).toBe('claude-opus-4-6');
      } finally {
        proxy.stop();
      }
    });

    it('rejects denylisted AGY 4.5 model IDs on antigravity provider route', async () => {
      const proxy = new ToolSanitizationProxy({
        upstreamBaseUrl: `http://127.0.0.1:${mockUpstreamPort}`,
      });
      const port = await proxy.start();

      try {
        const response = await fetch(`http://127.0.0.1:${port}/api/provider/agy/v1/messages`, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            model: 'claude-sonnet-4.5',
            messages: [{ role: 'user', content: 'test' }],
          }),
        });

        expect(response.status).toBe(400);
        const body = (await response.json()) as { error: string };
        expect(body.error).toContain('denylist');
        expect(lastRequest).toBeNull();
      } finally {
        proxy.stop();
      }
    });

    it('does not rewrite AGY legacy aliases on non-AGY provider routes', async () => {
      const proxy = new ToolSanitizationProxy({
        upstreamBaseUrl: `http://127.0.0.1:${mockUpstreamPort}`,
      });
      const port = await proxy.start();

      try {
        await fetch(`http://127.0.0.1:${port}/api/provider/claude/v1/messages`, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            model: 'claude-sonnet-4-6-thinking',
            messages: [{ role: 'user', content: 'test' }],
          }),
        });

        expect(lastRequest).not.toBeNull();
        expect((lastRequest!.body as Record<string, unknown>).model).toBe(
          'claude-sonnet-4-6-thinking'
        );
      } finally {
        proxy.stop();
      }
    });

    it('normalizes legacy iFlow aliases on explicit iflow provider routes', async () => {
      const proxy = new ToolSanitizationProxy({
        upstreamBaseUrl: `http://127.0.0.1:${mockUpstreamPort}`,
      });
      const port = await proxy.start();

      try {
        await fetch(`http://127.0.0.1:${port}/api/provider/iflow/v1/messages`, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            model: 'kimi-k2.5',
            messages: [{ role: 'user', content: 'test' }],
          }),
        });

        expect(lastRequest).not.toBeNull();
        expect((lastRequest!.body as Record<string, unknown>).model).toBe('kimi-k2');
      } finally {
        proxy.stop();
      }
    });

    it('strips Gemini-unsupported top-level tool fields while keeping schema sanitization', async () => {
      const proxy = new ToolSanitizationProxy({
        upstreamBaseUrl: `http://127.0.0.1:${mockUpstreamPort}`,
      });
      const port = await proxy.start();

      try {
        await fetch(`http://127.0.0.1:${port}/api/provider/gemini/v1/messages`, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            model: 'gemini-2.5-pro',
            tools: [
              {
                name: 'tool__with__duplicate__duplicate',
                description: 'Test description',
                strict: true,
                input_examples: [{ command: 'ls -la' }],
                type: 'custom',
                cache_control: { type: 'ephemeral' },
                defer_loading: true,
                input_schema: {
                  type: 'object',
                  properties: {
                    command: {
                      type: 'string',
                      examples: ['ls -la'],
                    },
                  },
                },
              },
            ],
          }),
        });

        const sentTools = (lastRequest!.body as Record<string, unknown>).tools as Array<
          Record<string, unknown>
        >;
        expect(sentTools[0].name).toBe('tool__with__duplicate');
        expect(sentTools[0].description).toBe('Test description');
        expect(sentTools[0].strict).toBeUndefined();
        expect(sentTools[0].input_examples).toBeUndefined();
        expect(sentTools[0].type).toBeUndefined();
        expect(sentTools[0].cache_control).toBeUndefined();
        expect(sentTools[0].defer_loading).toBeUndefined();
        expect(sentTools[0].input_schema).toEqual({
          type: 'object',
          properties: {
            command: {
              type: 'string',
            },
          },
        });
      } finally {
        proxy.stop();
      }
    });

    it('strips only Codex-unsupported top-level tool fields before forwarding', async () => {
      const proxy = new ToolSanitizationProxy({
        upstreamBaseUrl: `http://127.0.0.1:${mockUpstreamPort}`,
      });
      const port = await proxy.start();

      try {
        await fetch(`http://127.0.0.1:${port}/api/provider/codex/v1/messages`, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            model: 'gpt-5.3-codex',
            tools: [
              {
                name: 'codex_tool',
                description: 'Codex test',
                cache_control: { type: 'ephemeral' },
                defer_loading: true,
                input_schema: {
                  type: 'object',
                  properties: {
                    prompt: {
                      type: 'string',
                      examples: ['fix the failing test'],
                    },
                  },
                },
              },
            ],
          }),
        });

        const sentTools = (lastRequest!.body as Record<string, unknown>).tools as Array<
          Record<string, unknown>
        >;
        expect(sentTools[0].name).toBe('codex_tool');
        expect(sentTools[0].description).toBe('Codex test');
        expect(sentTools[0].cache_control).toBeUndefined();
        expect(sentTools[0].defer_loading).toBe(true);
        expect(sentTools[0].input_schema).toEqual({
          type: 'object',
          properties: {
            prompt: {
              type: 'string',
            },
          },
        });
      } finally {
        proxy.stop();
      }
    });

    for (const model of [
      'gpt-5.3-codex-xhigh',
      'gpt-5.1-codex-mini',
      'gpt-5.1-codex',
      'gpt-5-codex',
    ]) {
      it(`strips only Codex-unsupported top-level tool fields on root model-routed request (${model})`, async () => {
        const proxy = new ToolSanitizationProxy({
          upstreamBaseUrl: `http://127.0.0.1:${mockUpstreamPort}`,
        });
        const port = await proxy.start();

        try {
          await fetch(`http://127.0.0.1:${port}/v1/messages`, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({
              model,
              tools: [
                {
                  name: 'root_codex_tool',
                  description: 'Root-routed Codex test',
                  cache_control: { type: 'ephemeral' },
                  defer_loading: true,
                  input_schema: {
                    type: 'object',
                    properties: {
                      prompt: {
                        type: 'string',
                        examples: ['fix the failing test'],
                      },
                    },
                  },
                },
              ],
            }),
          });

          const sentTools = (lastRequest!.body as Record<string, unknown>).tools as Array<
            Record<string, unknown>
          >;
          expect(sentTools[0].name).toBe('root_codex_tool');
          expect(sentTools[0].description).toBe('Root-routed Codex test');
          expect(sentTools[0].cache_control).toBeUndefined();
          expect(sentTools[0].defer_loading).toBe(true);
          expect(sentTools[0].input_schema).toEqual({
            type: 'object',
            properties: {
              prompt: {
                type: 'string',
              },
            },
          });
        } finally {
          proxy.stop();
        }
      });
    }

    it('preserves top-level tool fields for non-target root routes', async () => {
      const proxy = new ToolSanitizationProxy({
        upstreamBaseUrl: `http://127.0.0.1:${mockUpstreamPort}`,
      });
      const port = await proxy.start();

      try {
        await fetch(`http://127.0.0.1:${port}/v1/messages`, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            model: 'claude-sonnet-4-6',
            tools: [
              {
                name: 'claude_tool__duplicate__duplicate',
                description: 'Anthropic passthrough test',
                cache_control: { type: 'ephemeral' },
                defer_loading: true,
                input_schema: {
                  type: 'object',
                  properties: {
                    prompt: {
                      type: 'string',
                      examples: ['keep these top-level fields'],
                    },
                  },
                },
              },
            ],
          }),
        });

        const sentTools = (lastRequest!.body as Record<string, unknown>).tools as Array<
          Record<string, unknown>
        >;
        expect(sentTools[0].name).toBe('claude_tool__duplicate');
        expect(sentTools[0].description).toBe('Anthropic passthrough test');
        expect(sentTools[0].cache_control).toEqual({ type: 'ephemeral' });
        expect(sentTools[0].defer_loading).toBe(true);
        expect(sentTools[0].input_schema).toEqual({
          type: 'object',
          properties: {
            prompt: {
              type: 'string',
            },
          },
        });
      } finally {
        proxy.stop();
      }
    });

    it('preserves other tool properties during sanitization', async () => {
      const proxy = new ToolSanitizationProxy({
        upstreamBaseUrl: `http://127.0.0.1:${mockUpstreamPort}`,
      });
      const port = await proxy.start();

      try {
        await fetch(`http://127.0.0.1:${port}/v1/messages`, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            tools: [
              {
                name: 'foo__bar__bar',
                description: 'Test description',
                input_schema: {
                  type: 'object',
                  properties: { x: { type: 'string', examples: ['demo'] } },
                },
              },
            ],
          }),
        });

        const sentTools = (lastRequest!.body as Record<string, unknown>).tools as Array<{
          name: string;
          description: string;
          input_schema: object;
        }>;
        expect(sentTools[0].name).toBe('foo__bar');
        expect(sentTools[0].description).toBe('Test description');
        expect(sentTools[0].input_schema).toEqual({
          type: 'object',
          properties: { x: { type: 'string' } },
        });
      } finally {
        proxy.stop();
      }
    });
  });

  describe('Response Restoration (Buffered)', () => {
    it('restores original tool names in tool_use response blocks', async () => {
      const proxy = new ToolSanitizationProxy({
        upstreamBaseUrl: `http://127.0.0.1:${mockUpstreamPort}`,
      });
      const port = await proxy.start();

      // Mock upstream returns sanitized name in tool_use
      mockResponse = {
        status: 200,
        body: {
          content: [
            { type: 'text', text: 'Using tool...' },
            { type: 'tool_use', id: 'call_123', name: 'foo__bar', input: { query: 'test' } },
          ],
        },
      };

      try {
        const response = await fetch(`http://127.0.0.1:${port}/v1/messages`, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            tools: [{ name: 'foo__bar__bar' }],
          }),
        });

        const data = (await response.json()) as { content: Array<{ type: string; name?: string }> };
        expect(data.content[0].type).toBe('text');
        expect(data.content[1].type).toBe('tool_use');
        expect(data.content[1].name).toBe('foo__bar__bar'); // Restored!
      } finally {
        proxy.stop();
      }
    });

    it('leaves unknown tool names unchanged in response', async () => {
      const proxy = new ToolSanitizationProxy({
        upstreamBaseUrl: `http://127.0.0.1:${mockUpstreamPort}`,
      });
      const port = await proxy.start();

      mockResponse = {
        status: 200,
        body: {
          content: [{ type: 'tool_use', id: 'call_456', name: 'unknown_tool', input: {} }],
        },
      };

      try {
        const response = await fetch(`http://127.0.0.1:${port}/v1/messages`, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            tools: [{ name: 'foo__bar__bar' }],
          }),
        });

        const data = (await response.json()) as { content: Array<{ name: string }> };
        expect(data.content[0].name).toBe('unknown_tool');
      } finally {
        proxy.stop();
      }
    });
  });

  describe('Response Restoration (Streaming)', () => {
    it('restores tool names in SSE streaming responses', async () => {
      const proxy = new ToolSanitizationProxy({
        upstreamBaseUrl: `http://127.0.0.1:${mockUpstreamPort}`,
      });
      const port = await proxy.start();

      // Mock SSE events with sanitized tool name
      mockResponse = {
        status: 200,
        stream: true,
        body: [
          'event: content_block_start\n',
          `data: ${JSON.stringify({ type: 'content_block_start', content_block: { type: 'tool_use', id: 'call_789', name: 'foo__bar' } })}\n\n`,
          'event: content_block_stop\n',
          'data: {"type":"content_block_stop"}\n\n',
        ],
      };

      try {
        const response = await fetch(`http://127.0.0.1:${port}/v1/messages`, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            stream: true,
            tools: [{ name: 'foo__bar__bar' }],
          }),
        });

        const text = await response.text();
        expect(text).toContain('foo__bar__bar'); // Restored in SSE
        expect(text).not.toContain('"name":"foo__bar"'); // Original sanitized name replaced
      } finally {
        proxy.stop();
      }
    });

    it('passes through SSE events when no sanitization occurred', async () => {
      const proxy = new ToolSanitizationProxy({
        upstreamBaseUrl: `http://127.0.0.1:${mockUpstreamPort}`,
      });
      const port = await proxy.start();

      mockResponse = {
        status: 200,
        stream: true,
        body: [
          'event: message_start\n',
          'data: {"type":"message_start"}\n\n',
          'event: content_block_delta\n',
          'data: {"type":"content_block_delta","delta":{"text":"Hello"}}\n\n',
        ],
      };

      try {
        const response = await fetch(`http://127.0.0.1:${port}/v1/messages`, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            stream: true,
            tools: [{ name: 'valid_tool' }], // No sanitization needed
          }),
        });

        const text = await response.text();
        expect(text).toContain('message_start');
        expect(text).toContain('content_block_delta');
      } finally {
        proxy.stop();
      }
    });
  });

  describe('Error Handling', () => {
    it('returns 400 for invalid JSON request body', async () => {
      const proxy = new ToolSanitizationProxy({
        upstreamBaseUrl: `http://127.0.0.1:${mockUpstreamPort}`,
      });
      const port = await proxy.start();

      try {
        const response = await fetch(`http://127.0.0.1:${port}/v1/messages`, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: 'not valid json{',
        });

        expect(response.status).toBe(400);
        const data = (await response.json()) as { error: string };
        expect(data.error).toContain('Invalid JSON');
      } finally {
        proxy.stop();
      }
    });

    it('forwards upstream errors correctly', async () => {
      const proxy = new ToolSanitizationProxy({
        upstreamBaseUrl: `http://127.0.0.1:${mockUpstreamPort}`,
      });
      const port = await proxy.start();

      mockResponse = {
        status: 429,
        body: { error: { type: 'rate_limit_error', message: 'Too many requests' } },
      };

      try {
        const response = await fetch(`http://127.0.0.1:${port}/v1/messages`, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ tools: [] }),
        });

        expect(response.status).toBe(429);
      } finally {
        proxy.stop();
      }
    });

    it('handles upstream connection errors gracefully', async () => {
      const originalNoProxy = process.env.NO_PROXY;
      const originalNoProxyLower = process.env.no_proxy;
      process.env.NO_PROXY = '127.0.0.1,localhost';
      process.env.no_proxy = '127.0.0.1,localhost';

      const proxy = new ToolSanitizationProxy({
        upstreamBaseUrl: 'http://127.0.0.1:1', // Invalid port
        timeoutMs: 1000,
      });
      const port = await proxy.start();

      try {
        const response = await fetch(`http://127.0.0.1:${port}/v1/messages`, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ tools: [] }),
        });

        expect(response.status).toBe(502);
      } finally {
        proxy.stop();
        if (originalNoProxy === undefined) {
          delete process.env.NO_PROXY;
        } else {
          process.env.NO_PROXY = originalNoProxy;
        }
        if (originalNoProxyLower === undefined) {
          delete process.env.no_proxy;
        } else {
          process.env.no_proxy = originalNoProxyLower;
        }
      }
    });
  });

  describe('Non-JSON Passthrough', () => {
    it('forwards GET requests without modification', async () => {
      const proxy = new ToolSanitizationProxy({
        upstreamBaseUrl: `http://127.0.0.1:${mockUpstreamPort}`,
      });
      const port = await proxy.start();

      mockResponse = { status: 200, body: { status: 'ok' } };

      try {
        const response = await fetch(`http://127.0.0.1:${port}/health`);
        expect(response.ok).toBe(true);
      } finally {
        proxy.stop();
      }
    });
  });

  describe('Multiple Tools Sanitization', () => {
    it('sanitizes multiple tools and tracks all mappings', async () => {
      const proxy = new ToolSanitizationProxy({
        upstreamBaseUrl: `http://127.0.0.1:${mockUpstreamPort}`,
      });
      const port = await proxy.start();

      mockResponse = {
        status: 200,
        body: {
          content: [
            { type: 'tool_use', id: '1', name: 'tool_a__x', input: {} },
            { type: 'tool_use', id: '2', name: 'tool_b__y', input: {} },
          ],
        },
      };

      try {
        const response = await fetch(`http://127.0.0.1:${port}/v1/messages`, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            tools: [{ name: 'tool_a__x__x' }, { name: 'tool_b__y__y' }, { name: 'tool_c_valid' }],
          }),
        });

        // Verify request was sanitized
        const sentTools = (lastRequest!.body as Record<string, unknown>).tools as Array<{
          name: string;
        }>;
        expect(sentTools[0].name).toBe('tool_a__x');
        expect(sentTools[1].name).toBe('tool_b__y');
        expect(sentTools[2].name).toBe('tool_c_valid');

        // Verify response was restored
        const data = (await response.json()) as { content: Array<{ name: string }> };
        expect(data.content[0].name).toBe('tool_a__x__x');
        expect(data.content[1].name).toBe('tool_b__y__y');
      } finally {
        proxy.stop();
      }
    });
  });

  describe('Empty Response Safety Net (Issue #350)', () => {
    it('injects synthetic response when streaming 200 has no content blocks', async () => {
      const proxy = new ToolSanitizationProxy({
        upstreamBaseUrl: `http://127.0.0.1:${mockUpstreamPort}`,
      });
      const port = await proxy.start();

      // Upstream sends message_start + message_delta + message_stop but NO content blocks
      mockResponse = {
        status: 200,
        stream: true,
        body: [
          'event: message_start\n',
          'data: {"type":"message_start","message":{"id":"msg_test","type":"message","role":"assistant","content":[],"model":"test","stop_reason":null}}\n\n',
          'event: message_delta\n',
          'data: {"type":"message_delta","delta":{"stop_reason":"end_turn"},"usage":{"input_tokens":10,"output_tokens":0}}\n\n',
          'event: message_stop\n',
          'data: {"type":"message_stop"}\n\n',
        ],
      };

      try {
        const response = await fetch(`http://127.0.0.1:${port}/v1/messages`, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            stream: true,
            tools: [{ name: 'valid_tool' }],
          }),
        });

        const text = await response.text();
        // Should contain the synthetic error message
        expect(text).toContain('[Proxy Error]');
        expect(text).toContain('content_block_start');
        expect(text).toContain('content_block_delta');
        expect(text).toContain('content_block_stop');
        // Should NOT have duplicate lifecycle events (upstream already sent them)
        const messageStartCount = (text.match(/"type":"message_start"/g) || []).length;
        expect(messageStartCount).toBe(1);
        const messageDeltaCount = (text.match(/"type":"message_delta"/g) || []).length;
        expect(messageDeltaCount).toBe(1);
        const messageStopCount = (text.match(/"type":"message_stop"/g) || []).length;
        expect(messageStopCount).toBe(1);
      } finally {
        proxy.stop();
      }
    });

    it('does NOT inject synthetic response when content blocks exist', async () => {
      const proxy = new ToolSanitizationProxy({
        upstreamBaseUrl: `http://127.0.0.1:${mockUpstreamPort}`,
      });
      const port = await proxy.start();

      mockResponse = {
        status: 200,
        stream: true,
        body: [
          'event: message_start\n',
          'data: {"type":"message_start","message":{"id":"msg_ok","type":"message","role":"assistant","content":[],"model":"test"}}\n\n',
          'event: content_block_start\n',
          'data: {"type":"content_block_start","index":0,"content_block":{"type":"text","text":""}}\n\n',
          'event: content_block_delta\n',
          'data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Hello"}}\n\n',
          'event: content_block_stop\n',
          'data: {"type":"content_block_stop","index":0}\n\n',
          'event: message_delta\n',
          'data: {"type":"message_delta","delta":{"stop_reason":"end_turn"}}\n\n',
          'event: message_stop\n',
          'data: {"type":"message_stop"}\n\n',
        ],
      };

      try {
        const response = await fetch(`http://127.0.0.1:${port}/v1/messages`, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            stream: true,
            tools: [{ name: 'valid_tool' }],
          }),
        });

        const text = await response.text();
        expect(text).toContain('Hello');
        expect(text).not.toContain('[Proxy Error]');
      } finally {
        proxy.stop();
      }
    });

    it('does NOT inject synthetic response for 4xx/5xx errors', async () => {
      const proxy = new ToolSanitizationProxy({
        upstreamBaseUrl: `http://127.0.0.1:${mockUpstreamPort}`,
      });
      const port = await proxy.start();

      // 429 rate limit with SSE body but no content blocks
      mockResponse = {
        status: 429,
        stream: true,
        body: [
          'event: error\n',
          'data: {"type":"error","error":{"type":"rate_limit_error","message":"Too many requests"}}\n\n',
        ],
      };

      try {
        const response = await fetch(`http://127.0.0.1:${port}/v1/messages`, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            stream: true,
            tools: [{ name: 'valid_tool' }],
          }),
        });

        expect(response.status).toBe(429);
        const text = await response.text();
        expect(text).not.toContain('[Proxy Error]');
        expect(text).toContain('rate_limit_error');
      } finally {
        proxy.stop();
      }
    });

    it('injects synthetic response via SSE processing path (with sanitized tool names)', async () => {
      const proxy = new ToolSanitizationProxy({
        upstreamBaseUrl: `http://127.0.0.1:${mockUpstreamPort}`,
      });
      const port = await proxy.start();

      // Upstream returns empty content — no content_block_start events
      // Using sanitized tool name ('foo__bar__bar' → 'foo__bar') triggers the SSE processing path
      mockResponse = {
        status: 200,
        stream: true,
        body: [
          'event: message_start\n',
          'data: {"type":"message_start","message":{"id":"msg_sse","type":"message","role":"assistant","content":[],"model":"test","stop_reason":null}}\n\n',
          'event: message_delta\n',
          'data: {"type":"message_delta","delta":{"stop_reason":"end_turn"},"usage":{"input_tokens":10,"output_tokens":0}}\n\n',
          'event: message_stop\n',
          'data: {"type":"message_stop"}\n\n',
        ],
      };

      try {
        const response = await fetch(`http://127.0.0.1:${port}/v1/messages`, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            stream: true,
            tools: [{ name: 'foo__bar__bar' }], // Triggers sanitization → SSE processing path
          }),
        });

        const text = await response.text();
        expect(text).toContain('[Proxy Error]');
        expect(text).toContain('content_block_start');
        // No duplicate lifecycle events
        const messageStartCount = (text.match(/"type":"message_start"/g) || []).length;
        expect(messageStartCount).toBe(1);
        const messageDeltaCount = (text.match(/"type":"message_delta"/g) || []).length;
        expect(messageDeltaCount).toBe(1);
        const messageStopCount = (text.match(/"type":"message_stop"/g) || []).length;
        expect(messageStopCount).toBe(1);
      } finally {
        proxy.stop();
      }
    });

    it('injects synthetic response when upstream sends only message_start (real failure mode)', async () => {
      const proxy = new ToolSanitizationProxy({
        upstreamBaseUrl: `http://127.0.0.1:${mockUpstreamPort}`,
      });
      const port = await proxy.start();

      // Real failure: upstream sends message_start then abruptly ends — no message_delta or message_stop
      mockResponse = {
        status: 200,
        stream: true,
        body: [
          'event: message_start\n',
          'data: {"type":"message_start","message":{"id":"msg_abrupt","type":"message","role":"assistant","content":[],"model":"test","stop_reason":null}}\n\n',
        ],
      };

      try {
        const response = await fetch(`http://127.0.0.1:${port}/v1/messages`, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            stream: true,
            tools: [{ name: 'valid_tool' }],
          }),
        });

        const text = await response.text();
        expect(text).toContain('[Proxy Error]');
        expect(text).toContain('content_block_start');
        expect(text).toContain('message_delta');
        expect(text).toContain('message_stop');
        // Only 1 of each — upstream sent message_start, synthetic provides the rest
        const messageStartCount = (text.match(/"type":"message_start"/g) || []).length;
        expect(messageStartCount).toBe(1);
        const messageDeltaCount = (text.match(/"type":"message_delta"/g) || []).length;
        expect(messageDeltaCount).toBe(1);
        const messageStopCount = (text.match(/"type":"message_stop"/g) || []).length;
        expect(messageStopCount).toBe(1);
      } finally {
        proxy.stop();
      }
    });
  });
});
