import { describe, it, expect, beforeEach, vi } from 'vitest';
import { createBowongTextVideoAgentService } from '../bowongTextVideoAgentService';
import type {
  BowongTextVideoAgentConfig,
  SyncImageGenerationRequest,
  VideoGenerationRequest,
  TaskResponse,
  ImageGenerationResponse,
  TaskStatusResponse
} from '../../types/bowongTextVideoAgent';

// Mock Tauri invoke
const mockInvoke = vi.fn();
vi.mock('@tauri-apps/api/core', () => ({
  invoke: mockInvoke
}));

describe('BowongTextVideoAgentService', () => {
  let service: any;
  let config: BowongTextVideoAgentConfig;

  beforeEach(() => {
    config = {
      baseUrl: 'https://api.bowong.com',
      apiKey: 'test-api-key',
      timeout: 30000,
      retryAttempts: 3,
      enableCache: true,
      maxConcurrency: 10
    };
    
    service = createBowongTextVideoAgentService(config);
    mockInvoke.mockClear();
  });

  describe('Service Initialization', () => {
    it('should initialize with correct config', () => {
      expect(service.config).toEqual(config);
    });

    it('should have default retry configuration', () => {
      expect(service.config.retryAttempts).toBe(3);
      expect(service.config.timeout).toBe(30000);
    });
  });

  describe('Prompt Module', () => {
    it('should call getSamplePrompt with correct command', async () => {
      const mockResponse = {
        status: true,
        message: 'Success',
        data: { prompt: 'Sample prompt' }
      };
      
      mockInvoke.mockResolvedValue(mockResponse);
      
      const result = await service.getSamplePrompt({ category: 'landscape' });
      
      expect(mockInvoke).toHaveBeenCalledWith('bowong_get_sample_prompt', { category: 'landscape' });
      expect(result).toEqual(mockResponse);
    });

    it('should call health check with correct command', async () => {
      const mockResponse = { status: true, message: 'Healthy' };
      mockInvoke.mockResolvedValue(mockResponse);
      
      const result = await service.checkPromptHealth();
      
      expect(mockInvoke).toHaveBeenCalledWith('bowong_health_check');
      expect(result).toEqual(mockResponse);
    });
  });

  describe('File Upload Module', () => {
    it('should upload file with correct command', async () => {
      const mockResponse = {
        file_url: 'https://example.com/file.jpg',
        file_id: 'file-123',
        message: 'Upload successful'
      };
      
      const uploadRequest = {
        file_data: new Uint8Array([1, 2, 3]),
        filename: 'test.jpg',
        content_type: 'image/jpeg'
      };
      
      mockInvoke.mockResolvedValue(mockResponse);
      
      const result = await service.uploadFile(uploadRequest);
      
      expect(mockInvoke).toHaveBeenCalledWith('bowong_upload_file', uploadRequest);
      expect(result).toEqual(mockResponse);
    });

    it('should upload file to S3 with correct command', async () => {
      const mockResponse = {
        file_url: 'https://s3.example.com/file.jpg',
        file_id: 's3-file-123',
        message: 'S3 upload successful'
      };
      
      const s3Request = {
        file_data: new Uint8Array([1, 2, 3]),
        filename: 'test.jpg',
        content_type: 'image/jpeg'
      };
      
      mockInvoke.mockResolvedValue(mockResponse);
      
      const result = await service.uploadFileToS3(s3Request);
      
      expect(mockInvoke).toHaveBeenCalledWith('bowong_upload_file_to_s3', s3Request);
      expect(result).toEqual(mockResponse);
    });
  });

  describe('Midjourney Image Generation', () => {
    it('should generate image synchronously', async () => {
      const mockResponse: ImageGenerationResponse = {
        image_url: 'https://example.com/generated.jpg',
        task_id: 'img-task-123',
        status: 'completed',
        message: 'Image generated successfully'
      };
      
      const request: SyncImageGenerationRequest = {
        prompt: 'A beautiful landscape',
        img_file: 'https://example.com/ref.jpg',
        max_wait_time: 120,
        poll_interval: 2
      };
      
      mockInvoke.mockResolvedValue(mockResponse);
      
      const result = await service.syncGenerateImage(request);
      
      expect(mockInvoke).toHaveBeenCalledWith('bowong_sync_generate_image', request);
      expect(result).toEqual(mockResponse);
    });

    it('should generate image asynchronously', async () => {
      const mockResponse: TaskResponse = {
        task_id: 'async-img-123',
        status: 'pending',
        message: 'Task submitted'
      };
      
      const request = {
        prompt: 'A beautiful landscape',
        img_file: 'https://example.com/ref.jpg',
        max_wait_time: 120,
        poll_interval: 2
      };
      
      mockInvoke.mockResolvedValue(mockResponse);
      
      const result = await service.asyncGenerateImage(request);
      
      expect(mockInvoke).toHaveBeenCalledWith('bowong_async_generate_image', request);
      expect(result).toEqual(mockResponse);
    });

    it('should query task status', async () => {
      const mockResponse: TaskStatusResponse = {
        task_id: 'task-123',
        status: 'completed',
        progress: 100,
        result: { image_url: 'https://example.com/result.jpg' },
        error: null,
        created_at: '2024-01-01T00:00:00Z',
        updated_at: '2024-01-01T00:00:00Z'
      };
      
      mockInvoke.mockResolvedValue(mockResponse);
      
      const result = await service.queryImageTaskStatus('task-123');
      
      expect(mockInvoke).toHaveBeenCalledWith('bowong_get_task_status', 'task-123');
      expect(result).toEqual(mockResponse);
    });
  });

  describe('Video Generation', () => {
    it('should generate video asynchronously', async () => {
      const mockResponse: TaskResponse = {
        task_id: 'video-task-123',
        status: 'pending',
        message: 'Video generation started'
      };
      
      const request: VideoGenerationRequest = {
        prompt: 'A video of nature',
        img_url: 'https://example.com/ref.jpg',
        duration: 10,
        max_wait_time: 300,
        poll_interval: 5
      };
      
      mockInvoke.mockResolvedValue(mockResponse);
      
      const result = await service.asyncGenerateVideo(request);
      
      expect(mockInvoke).toHaveBeenCalledWith('bowong_generate_video', request);
      expect(result).toEqual(mockResponse);
    });

    it('should query video task status', async () => {
      const mockResponse: TaskStatusResponse = {
        task_id: 'video-task-123',
        status: 'processing',
        progress: 50,
        result: null,
        error: null,
        created_at: '2024-01-01T00:00:00Z',
        updated_at: '2024-01-01T00:00:00Z'
      };
      
      mockInvoke.mockResolvedValue(mockResponse);
      
      const result = await service.queryVideoTaskStatus('video-task-123');
      
      expect(mockInvoke).toHaveBeenCalledWith('bowong_get_task_status', 'video-task-123');
      expect(result).toEqual(mockResponse);
    });
  });

  describe('Task Management', () => {
    it('should create task', async () => {
      const mockResponse: TaskResponse = {
        task_id: 'new-task-123',
        status: 'pending',
        message: 'Task created'
      };
      
      const request = {
        type: 'image_generation',
        params: { prompt: 'Test prompt' }
      };
      
      mockInvoke.mockResolvedValue(mockResponse);
      
      const result = await service.createTask(request);
      
      expect(mockInvoke).toHaveBeenCalledWith('bowong_create_task', request);
      expect(result).toEqual(mockResponse);
    });

    it('should get task status', async () => {
      const mockResponse: TaskStatusResponse = {
        task_id: 'task-123',
        status: 'completed',
        progress: 100,
        result: { output: 'success' },
        error: null,
        created_at: '2024-01-01T00:00:00Z',
        updated_at: '2024-01-01T00:00:00Z'
      };
      
      mockInvoke.mockResolvedValue(mockResponse);
      
      const result = await service.getTaskStatus('task-123');
      
      expect(mockInvoke).toHaveBeenCalledWith('bowong_get_task_status', 'task-123');
      expect(result).toEqual(mockResponse);
    });
  });

  describe('Error Handling', () => {
    it('should handle Tauri invoke errors', async () => {
      const error = new Error('Tauri invoke failed');
      mockInvoke.mockRejectedValue(error);
      
      await expect(service.getSamplePrompt()).rejects.toThrow('Tauri invoke failed');
    });

    it('should handle network timeout errors', async () => {
      const timeoutError = new Error('Request timeout');
      mockInvoke.mockRejectedValue(timeoutError);
      
      await expect(service.checkPromptHealth()).rejects.toThrow('Request timeout');
    });
  });

  describe('Service Configuration', () => {
    it('should use correct configuration values', () => {
      expect(service.config.baseUrl).toBe('https://api.bowong.com');
      expect(service.config.apiKey).toBe('test-api-key');
      expect(service.config.timeout).toBe(30000);
      expect(service.config.retryAttempts).toBe(3);
      expect(service.config.enableCache).toBe(true);
      expect(service.config.maxConcurrency).toBe(10);
    });

    it('should handle missing optional config values', () => {
      const minimalConfig = {
        baseUrl: 'https://api.bowong.com',
        apiKey: 'test-key'
      };
      
      const minimalService = createBowongTextVideoAgentService(minimalConfig);
      expect(minimalService.config.baseUrl).toBe('https://api.bowong.com');
      expect(minimalService.config.apiKey).toBe('test-key');
    });
  });
});
