/**
 * Integration tests for Get Components Guide MCP Tool
 * These tests verify the tool's behavior with mocked GitLab responses
 */

// Mock the GitLab client module
const mockFetchGitLabFileContentSafe = jest.fn();

jest.mock('../../services/gitlabClient', () => ({
  fetchGitLabFileContentSafe: mockFetchGitLabFileContentSafe,
  GitLabError: class GitLabError extends Error {
    constructor(message: string, public statusCode?: number, public url?: string) {
      super(message);
      this.name = 'GitLabError';
    }
  }
}));

import { getComponentsGuideTool } from '../../tools/getComponentsGuide';

// Mock the config
jest.mock('../../config', () => ({
  config: {
    urls: {
      gitlabBase: 'https://gitlab.example.com/repo/-/raw/main/'
    },
    auth: {
      gitlabToken: 'test-token'
    },
    internalGitlabHost: 'gitlab.example.com',
    // GitLab MCP settings for relative paths
    internalGuidesProjectId: 'test-project'
  }
}));

describe('Get Components Guide Tool Integration Tests', () => {
  beforeEach(() => {
    jest.clearAllMocks();
    jest.spyOn(console, 'log').mockImplementation(() => {});
    jest.spyOn(console, 'error').mockImplementation(() => {});

    // Reset global fetch mock
    if (global.fetch && jest.isMockFunction(global.fetch)) {
      (global.fetch as jest.Mock).mockReset();
    }
  });

  afterEach(() => {
    jest.restoreAllMocks();
  });

  describe('Successful execution scenarios', () => {
    const mockGuideContent = `# Dynamic Password Component

This component provides secure dynamic password generation functionality for payment systems.

## Installation

\`\`\`bash
npm install @yeepay/dynamic-password
\`\`\`

## Basic Usage

\`\`\`javascript
import { generatePassword } from '@yeepay/dynamic-password';

const password = generatePassword({
  length: 12,
  includeSpecialChars: true
});
\`\`\`

## Configuration

The component supports various configuration options:

- \`length\`: Password length (default: 8)
- \`includeSpecialChars\`: Include special characters (default: false)
- \`excludeSimilar\`: Exclude similar characters (default: true)

## API Reference

### generatePassword(options)

Generates a secure dynamic password.

**Parameters:**
- \`options\` (Object): Configuration options

**Returns:**
- \`string\`: Generated password`;

    it('should generate GitLab MCP instruction for relative path', async () => {
      const result = await getComponentsGuideTool({
        path: 'yeepay/dynamicpassword/llms.txt'
      });

      expect(result.content).toHaveLength(1);
      expect(result.content[0].type).toBe('text');
      expect(result.content[0].text).toContain('# Component Guide - GitLab MCP Instruction');
      expect(result.content[0].text).toContain('get_file_contents');
      expect(result.content[0].text).toContain('test-project');
      expect(result.content[0].text).toContain('yeepay/dynamicpassword/llms.txt');
      expect(result.isError).toBeUndefined();

      // Should not call GitLab client directly
      expect(mockFetchGitLabFileContentSafe).not.toHaveBeenCalled();
    });

    it('should execute successfully with absolute URL', async () => {
      const absoluteUrl = 'https://external.gitlab.com/project/-/raw/main/component/guide.txt';

      // Mock fetch for external URL (since it's external, it should use fetch, not GitLab client)
      global.fetch = jest.fn().mockResolvedValueOnce({
        ok: true,
        status: 200,
        text: jest.fn().mockResolvedValueOnce(mockGuideContent)
      } as any);

      const result = await getComponentsGuideTool({ path: absoluteUrl });

      expect(result.content).toHaveLength(1);
      expect(result.content[0].text).toContain('# Component Guide: Dynamic Password Component');
      expect(result.content[0].text).toContain(`**Source Path:** \`${absoluteUrl}\``);
      expect(result.isError).toBeUndefined();

      expect(global.fetch).toHaveBeenCalledWith(absoluteUrl, {
        headers: {
          'User-Agent': 'awesome-components-mcp/1.0.0'
        }
      });
    });

    it('should generate GitLab MCP instruction for path with leading slash', async () => {
      const result = await getComponentsGuideTool({
        path: '/yeepay/dynamicpassword/llms.txt'
      });

      expect(result.content).toHaveLength(1);
      expect(result.content[0].text).toContain('# Component Guide - GitLab MCP Instruction');
      expect(result.content[0].text).toContain('yeepay/dynamicpassword/llms.txt');
      expect(result.isError).toBeUndefined();

      // Should not call GitLab client directly
      expect(mockFetchGitLabFileContentSafe).not.toHaveBeenCalled();
    });

    it('should generate GitLab MCP instruction for markdown file', async () => {
      const result = await getComponentsGuideTool({
        path: 'component/guide.md'
      });

      expect(result.content[0].text).toContain('# Component Guide - GitLab MCP Instruction');
      expect(result.content[0].text).toContain('component/guide.md');
      expect(result.isError).toBeUndefined();

      // Should not call GitLab client directly
      expect(mockFetchGitLabFileContentSafe).not.toHaveBeenCalled();
    });

    it('should generate GitLab MCP instruction for empty path', async () => {
      const result = await getComponentsGuideTool({
        path: 'empty/component.txt'
      });

      expect(result.content[0].text).toContain('# Component Guide - GitLab MCP Instruction');
      expect(result.content[0].text).toContain('empty/component.txt');
      expect(result.isError).toBeUndefined();

      // Should not call GitLab client directly
      expect(mockFetchGitLabFileContentSafe).not.toHaveBeenCalled();
    });
  });

  describe('Path validation and error scenarios', () => {
    it('should reject invalid paths with dangerous characters', async () => {
      const result = await getComponentsGuideTool({ 
        path: '../../../etc/passwd' 
      });

      expect(result.content).toHaveLength(1);
      expect(result.content[0].text).toContain('Error: Invalid Component Guide Path');
      expect(result.content[0].text).toContain('invalid characters or format');
      expect(result.isError).toBe(true);
      
      expect(mockFetchGitLabFileContentSafe).not.toHaveBeenCalled();
    });

    it('should reject paths with script injection attempts', async () => {
      const result = await getComponentsGuideTool({ 
        path: 'path<script>alert(1)</script>' 
      });

      expect(result.content[0].text).toContain('Error: Invalid Component Guide Path');
      expect(result.isError).toBe(true);
      expect(mockFetchGitLabFileContentSafe).not.toHaveBeenCalled();
    });

    it('should reject empty paths', async () => {
      const result = await getComponentsGuideTool({ path: '' });

      expect(result.content[0].text).toContain('Error: Invalid Component Guide Path');
      expect(result.isError).toBe(true);
      expect(mockFetchGitLabFileContentSafe).not.toHaveBeenCalled();
    });

    it('should generate GitLab MCP instruction for nonexistent path', async () => {
      const result = await getComponentsGuideTool({
        path: 'nonexistent/component.txt'
      });

      expect(result.content).toHaveLength(1);
      expect(result.content[0].text).toContain('# Component Guide - GitLab MCP Instruction');
      expect(result.content[0].text).toContain('nonexistent/component.txt');
      expect(result.isError).toBeUndefined();

      // Should not call GitLab client directly
      expect(mockFetchGitLabFileContentSafe).not.toHaveBeenCalled();
    });

    it('should generate GitLab MCP instruction for private path', async () => {
      const result = await getComponentsGuideTool({
        path: 'private/component.txt'
      });

      expect(result.content[0].text).toContain('# Component Guide - GitLab MCP Instruction');
      expect(result.content[0].text).toContain('private/component.txt');
      expect(result.isError).toBeUndefined();

      // Should not call GitLab client directly
      expect(mockFetchGitLabFileContentSafe).not.toHaveBeenCalled();
    });

    it('should generate GitLab MCP instruction for any relative path', async () => {
      const result = await getComponentsGuideTool({
        path: 'component/guide.txt'
      });

      expect(result.content[0].text).toContain('# Component Guide - GitLab MCP Instruction');
      expect(result.content[0].text).toContain('component/guide.txt');
      expect(result.isError).toBeUndefined();

      // Should not call GitLab client directly
      expect(mockFetchGitLabFileContentSafe).not.toHaveBeenCalled();
    });
  });

  describe('Tool behavior verification', () => {
    it('should log the correct path and GitLab MCP instruction generation', async () => {
      const consoleSpy = jest.spyOn(console, 'log');

      await getComponentsGuideTool({ path: 'yeepay/component/llms.txt' });

      expect(consoleSpy).toHaveBeenCalledWith('Getting component guide for path: yeepay/component/llms.txt');
      expect(consoleSpy).toHaveBeenCalledWith('Relative/internal path detected, generating gitlab-mcp instruction: yeepay/component/llms.txt');
    });

    it('should return MCP-compliant response structure', async () => {
      const result = await getComponentsGuideTool({ path: 'test/component.txt' });

      // Verify MCP response structure
      expect(result).toHaveProperty('content');
      expect(Array.isArray(result.content)).toBe(true);
      expect(result.content).toHaveLength(1);
      expect(result.content[0]).toHaveProperty('type', 'text');
      expect(result.content[0]).toHaveProperty('text');
      expect(typeof result.content[0].text).toBe('string');
    });

    it('should handle different path types correctly', async () => {
      // Test relative path - should generate GitLab MCP instruction
      const result1 = await getComponentsGuideTool({ path: 'component/guide.txt' });
      expect(result1.content[0].text).toContain('# Component Guide - GitLab MCP Instruction');
      expect(mockFetchGitLabFileContentSafe).not.toHaveBeenCalled();

      // Test path with leading slash - should generate GitLab MCP instruction
      const result2 = await getComponentsGuideTool({ path: '/component/guide.txt' });
      expect(result2.content[0].text).toContain('# Component Guide - GitLab MCP Instruction');

      // Test external URL (should use fetch, not GitLab client)
      const externalUrl = 'https://external.com/file.txt';

      // Mock fetch for external URL
      global.fetch = jest.fn().mockResolvedValueOnce({
        ok: true,
        status: 200,
        text: jest.fn().mockResolvedValueOnce('external content')
      } as any);

      const result3 = await getComponentsGuideTool({ path: externalUrl });

      // Should use fetch, not GitLab client
      expect(global.fetch).toHaveBeenCalledWith(externalUrl, {
        headers: {
          'User-Agent': 'awesome-components-mcp/1.0.0'
        }
      });
      expect(result3.content[0].text).toContain('# Component Guide: file');
      expect(mockFetchGitLabFileContentSafe).not.toHaveBeenCalledWith(externalUrl);
    });
  });
});
