/**
 * Integration tests for Components Discovery 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 { componentsDiscoveryTool } from '../../tools/componentsDiscovery';

// Mock the config
jest.mock('../../config', () => ({
  config: {
    urls: {
      gitlabBase: 'https://gitlab.example.com/repo/-/raw/main/',
      mainLlms: 'https://gitlab.example.com/repo/-/raw/main/llms.txt'
    },
    auth: {
      gitlabToken: 'test-token'
    },
    llmsTxtUrl: 'https://gitlab.example.com/repo/-/raw/main/llms.txt',
    llmsTxtProjectId: null,
    llmsTxtFile: null,
    gitlabMcpServerAddress: null,
    internalGitlabHost: null,
    internalGuidesProjectId: null
  }
}));

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

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

  describe('Direct fetch mode (LLMS_TXT_URL configured)', () => {
    const mockLlmsContent = `# Awesome Components

button-component
input-component
modal-component
guide/getting-started
docs/api-reference.md
tutorial/basic-usage
// This is a comment
another-component`;

    it('should execute successfully and return JSON format', async () => {
      mockFetchGitLabFileContentSafe.mockResolvedValueOnce(mockLlmsContent);

      const result = await componentsDiscoveryTool();

      expect(result.content).toHaveLength(1);
      expect(result.content[0].type).toBe('text');

      // Parse the JSON response
      const jsonData = JSON.parse(result.content[0].text);
      expect(jsonData).toHaveProperty('source');
      expect(jsonData).toHaveProperty('totalComponents', 7);
      expect(jsonData).toHaveProperty('componentsByType');
      expect(jsonData).toHaveProperty('components');
      expect(jsonData.components).toHaveLength(7);
      expect(result.isError).toBeUndefined();

      expect(mockFetchGitLabFileContentSafe).toHaveBeenCalledWith(
        'https://gitlab.example.com/repo/-/raw/main/llms.txt'
      );
    });

    it('should categorize components correctly', async () => {
      mockFetchGitLabFileContentSafe.mockResolvedValueOnce(mockLlmsContent);

      const result = await componentsDiscoveryTool();

      const jsonData = JSON.parse(result.content[0].text);

      expect(jsonData.componentsByType).toEqual({
        component: 4,
        guide: 1,
        documentation: 1,
        tutorial: 1
      });

      // Check specific components
      const buttonComponent = jsonData.components.find((c: any) => c.name === 'button-component');
      expect(buttonComponent).toEqual({
        name: 'button-component',
        type: 'component',
        path: 'button-component'
      });

      const guideComponent = jsonData.components.find((c: any) => c.name === 'getting-started');
      expect(guideComponent).toEqual({
        name: 'getting-started',
        type: 'guide',
        path: 'guide/getting-started'
      });

      expect(result.isError).toBeUndefined();
    });

    it('should handle empty content gracefully', async () => {
      mockFetchGitLabFileContentSafe.mockResolvedValueOnce('');

      const result = await componentsDiscoveryTool();

      expect(result.content).toHaveLength(1);
      const jsonData = JSON.parse(result.content[0].text);
      expect(jsonData.totalComponents).toBe(0);
      expect(jsonData.components).toEqual([]);
      expect(jsonData.componentsByType).toEqual({});
      expect(result.isError).toBeUndefined();
    });
  });

  // Note: GitLab MCP instruction mode tests would require more complex mocking
  // For now, we'll test the direct fetch mode which is the current default

  describe('Error handling scenarios', () => {
    it('should handle GitLab errors gracefully', async () => {
      const { GitLabError } = require('../../services/gitlabClient');
      const gitlabError = new GitLabError('File not found', 404, 'https://example.com/file.txt');
      mockFetchGitLabFileContentSafe.mockRejectedValueOnce(gitlabError);

      const result = await componentsDiscoveryTool();

      expect(result.content).toHaveLength(1);
      expect(result.content[0].text).toContain('Error: Components Discovery Failed');
      expect(result.content[0].text).toContain('GitLab Error: File not found');
      expect(result.content[0].text).toContain('**Status Code:** 404');
      expect(result.isError).toBe(true);
    });

    it('should handle network errors gracefully', async () => {
      mockFetchGitLabFileContentSafe.mockRejectedValueOnce(new Error('Network timeout'));

      const result = await componentsDiscoveryTool();

      expect(result.content).toHaveLength(1);
      expect(result.content[0].text).toContain('Error: Components Discovery Failed');
      expect(result.content[0].text).toContain('Error: Network timeout');
      expect(result.isError).toBe(true);
    });

    it('should handle unexpected errors gracefully', async () => {
      mockFetchGitLabFileContentSafe.mockRejectedValueOnce('Unexpected error type');

      const result = await componentsDiscoveryTool();

      expect(result.content).toHaveLength(1);
      expect(result.content[0].text).toContain('Error: Components Discovery Failed');
      expect(result.content[0].text).toContain('Error: Unexpected error type');
      expect(result.isError).toBe(true);
    });
  });

  describe('Tool behavior verification', () => {
    it('should log the correct URL being fetched', async () => {
      const consoleSpy = jest.spyOn(console, 'log');
      mockFetchGitLabFileContentSafe.mockResolvedValueOnce('test content');

      await componentsDiscoveryTool();

      expect(consoleSpy).toHaveBeenCalledWith(
        'Fetching components list from: https://gitlab.example.com/repo/-/raw/main/llms.txt'
      );
    });

    it('should call GitLab client with correct URL', async () => {
      mockFetchGitLabFileContentSafe.mockResolvedValueOnce('test content');

      await componentsDiscoveryTool();

      expect(mockFetchGitLabFileContentSafe).toHaveBeenCalledTimes(1);
      expect(mockFetchGitLabFileContentSafe).toHaveBeenCalledWith(
        'https://gitlab.example.com/repo/-/raw/main/llms.txt'
      );
    });

    it('should return MCP-compliant response structure with valid JSON', async () => {
      mockFetchGitLabFileContentSafe.mockResolvedValueOnce('test content');

      const result = await componentsDiscoveryTool();

      // 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');

      // Verify the content is valid JSON
      expect(() => JSON.parse(result.content[0].text)).not.toThrow();
      const jsonData = JSON.parse(result.content[0].text);
      expect(jsonData).toHaveProperty('source');
      expect(jsonData).toHaveProperty('totalComponents');
      expect(jsonData).toHaveProperty('componentsByType');
      expect(jsonData).toHaveProperty('components');
    });
  });
});
