import axios from 'axios';
import { AIImageGeneratorClient } from './client';

// Mock axios
jest.mock('axios');
const mockedAxios = axios as jest.Mocked<typeof axios>;

describe('AIImageGeneratorClient', () => {
  let client: AIImageGeneratorClient;

  beforeEach(() => {
    // Reset mocks
    jest.clearAllMocks();

    // Create a mock axios instance
    mockedAxios.create.mockReturnValue(mockedAxios as any);

    // Initialize client
    client = new AIImageGeneratorClient({
      baseUrl: 'https://api.example.com',
      apiKey: 'test-api-key',
    });
  });

  describe('generateImage', () => {
    it('should generate an image and return the URL', async () => {
      // Mock response
      mockedAxios.get.mockResolvedValueOnce({
        request: {
          res: {
            responseUrl: 'https://cdn.example.com/images/generated-123.png',
          },
        },
        headers: {
          location: 'https://cdn.example.com/images/generated-123.png',
        },
      });

      const result = await client.generateImage({
        width: 512,
        height: 512,
        prompt: 'Test prompt',
      });

      // Check that axios was called correctly
      expect(mockedAxios.get).toHaveBeenCalledWith('/images/image-gen', {
        params: expect.any(URLSearchParams),
      });

      // Check parameters
      const params = (mockedAxios.get.mock.calls[0][1] as any).params;
      expect(params.get('width')).toBe('512');
      expect(params.get('height')).toBe('512');
      expect(params.get('prompt')).toBe('Test prompt');

      // Check result
      expect(result).toBe('https://cdn.example.com/images/generated-123.png');
    });
  });

  describe('getSupportedModels', () => {
    it('should return supported models', async () => {
      // Mock response
      mockedAxios.get.mockResolvedValueOnce({
        data: [
          {
            id: 'dall-e-2',
            name: 'DALL-E 2',
            description: 'OpenAI DALL-E 2 model',
            maxWidth: 1024,
            maxHeight: 1024,
          },
        ],
        status: 200,
        statusText: 'OK',
      });

      const result = await client.getSupportedModels();

      // Check that axios was called correctly
      expect(mockedAxios.get).toHaveBeenCalledWith('/images/supported-models');

      // Check result
      expect(result.status).toBe(200);
      expect(result.data).toEqual([
        {
          id: 'dall-e-2',
          name: 'DALL-E 2',
          description: 'OpenAI DALL-E 2 model',
          maxWidth: 1024,
          maxHeight: 1024,
        },
      ]);
    });
  });

  describe('getSupportedSizes', () => {
    it('should return supported sizes', async () => {
      // Mock response
      mockedAxios.get.mockResolvedValueOnce({
        data: [
          { width: 512, height: 512, aspectRatio: '1:1' },
          { width: 1024, height: 768, aspectRatio: '4:3' },
        ],
        status: 200,
        statusText: 'OK',
      });

      const result = await client.getSupportedSizes();

      // Check that axios was called correctly
      expect(mockedAxios.get).toHaveBeenCalledWith('/images/supported-sizes');

      // Check result
      expect(result.status).toBe(200);
      expect(result.data).toEqual([
        { width: 512, height: 512, aspectRatio: '1:1' },
        { width: 1024, height: 768, aspectRatio: '4:3' },
      ]);
    });
  });

  describe('resizeImage', () => {
    it('should resize an image and return the URL', async () => {
      // Mock response
      mockedAxios.get.mockResolvedValueOnce({
        request: {
          res: {
            responseUrl: 'https://cdn.example.com/images/resized-123.png',
          },
        },
        headers: {
          location: 'https://cdn.example.com/images/resized-123.png',
        },
      });

      const result = await client.resizeImage('image-123', {
        width: 256,
        height: 256,
        format: 'png',
        quality: 80,
      });

      // Check that axios was called correctly
      expect(mockedAxios.get).toHaveBeenCalledWith(
        '/images/process/resize/image-123',
        {
          params: expect.any(URLSearchParams),
        },
      );

      // Check parameters
      const params = (mockedAxios.get.mock.calls[0][1] as any).params;
      expect(params.get('width')).toBe('256');
      expect(params.get('height')).toBe('256');
      expect(params.get('format')).toBe('png');
      expect(params.get('quality')).toBe('80');

      // Check result
      expect(result).toBe('https://cdn.example.com/images/resized-123.png');
    });
  });

  describe('convertImage', () => {
    it('should convert an image and return the URL', async () => {
      // Mock response
      mockedAxios.get.mockResolvedValueOnce({
        request: {
          res: {
            responseUrl: 'https://cdn.example.com/images/converted-123.webp',
          },
        },
        headers: {
          location: 'https://cdn.example.com/images/converted-123.webp',
        },
      });

      const result = await client.convertImage('image-123', {
        format: 'webp',
        quality: 85,
      });

      // Check that axios was called correctly
      expect(mockedAxios.get).toHaveBeenCalledWith(
        '/images/process/convert/image-123',
        {
          params: expect.any(URLSearchParams),
        },
      );

      // Check parameters
      const params = (mockedAxios.get.mock.calls[0][1] as any).params;
      expect(params.get('format')).toBe('webp');
      expect(params.get('quality')).toBe('85');

      // Check result
      expect(result).toBe('https://cdn.example.com/images/converted-123.webp');
    });
  });

  describe('optimizeImage', () => {
    it('should optimize an image and return the URL', async () => {
      // Mock response
      mockedAxios.get.mockResolvedValueOnce({
        request: {
          res: {
            responseUrl: 'https://cdn.example.com/images/optimized-123.jpg',
          },
        },
        headers: {
          location: 'https://cdn.example.com/images/optimized-123.jpg',
        },
      });

      const result = await client.optimizeImage('image-123', {
        format: 'jpeg',
        quality: 75,
      });

      // Check that axios was called correctly
      expect(mockedAxios.get).toHaveBeenCalledWith(
        '/images/process/optimize/image-123',
        {
          params: expect.any(URLSearchParams),
        },
      );

      // Check parameters
      const params = (mockedAxios.get.mock.calls[0][1] as any).params;
      expect(params.get('format')).toBe('jpeg');
      expect(params.get('quality')).toBe('75');

      // Check result
      expect(result).toBe('https://cdn.example.com/images/optimized-123.jpg');
    });
  });

  describe('getSupportedFormats', () => {
    it('should return supported formats', async () => {
      // Mock response
      mockedAxios.get.mockResolvedValueOnce({
        data: [
          {
            id: 'png',
            name: 'PNG',
            mimeType: 'image/png',
            extensions: ['.png'],
          },
          {
            id: 'jpeg',
            name: 'JPEG',
            mimeType: 'image/jpeg',
            extensions: ['.jpg', '.jpeg'],
          },
          {
            id: 'webp',
            name: 'WebP',
            mimeType: 'image/webp',
            extensions: ['.webp'],
          },
        ],
        status: 200,
        statusText: 'OK',
      });

      const result = await client.getSupportedFormats();

      // Check that axios was called correctly
      expect(mockedAxios.get).toHaveBeenCalledWith('/images/process/formats');

      // Check result
      expect(result.status).toBe(200);
      expect(result.data).toEqual([
        { id: 'png', name: 'PNG', mimeType: 'image/png', extensions: ['.png'] },
        {
          id: 'jpeg',
          name: 'JPEG',
          mimeType: 'image/jpeg',
          extensions: ['.jpg', '.jpeg'],
        },
        {
          id: 'webp',
          name: 'WebP',
          mimeType: 'image/webp',
          extensions: ['.webp'],
        },
      ]);
    });
  });

  describe('getMetrics', () => {
    it('should return API metrics', async () => {
      // Mock response
      mockedAxios.get.mockResolvedValueOnce({
        data: {
          uptime: 86400,
          requestCount: 1000,
          successRate: 99.5,
          averageResponseTime: 250,
        },
        status: 200,
        statusText: 'OK',
      });

      const result = await client.getMetrics();

      // Check that axios was called correctly
      expect(mockedAxios.get).toHaveBeenCalledWith('/monitoring/metrics');

      // Check result
      expect(result.status).toBe(200);
      expect(result.data).toEqual({
        uptime: 86400,
        requestCount: 1000,
        successRate: 99.5,
        averageResponseTime: 250,
      });
    });
  });

  describe('checkHealth', () => {
    it('should return health status', async () => {
      // Mock response
      mockedAxios.get.mockResolvedValueOnce({
        data: {
          status: 'UP',
          details: {
            database: { status: 'UP' },
            storage: { status: 'UP' },
            aiService: { status: 'UP' },
          },
        },
        status: 200,
        statusText: 'OK',
      });

      const result = await client.checkHealth();

      // Check that axios was called correctly
      expect(mockedAxios.get).toHaveBeenCalledWith('/monitoring/health');

      // Check result
      expect(result.status).toBe(200);
      expect(result.data).toEqual({
        status: 'UP',
        details: {
          database: { status: 'UP' },
          storage: { status: 'UP' },
          aiService: { status: 'UP' },
        },
      });
    });
  });
});
