/**
 * BowongTextVideoAgent 服务单元测试
 */

import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
import { invoke } from '@tauri-apps/api/core';
import {
  BowongTextVideoAgentFastApiService,
  createBowongTextVideoAgentService,
  initializeDefaultService,
  getDefaultBowongTextVideoAgentService,
  resetDefaultService,
} from '../services/bowongTextVideoAgentService';
import {
  BowongTextVideoAgentConfig,
  TaskStatus,
  ValidationError,
  TaskFailedError,
} from '../types/bowongTextVideoAgent';

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

const mockInvoke = vi.mocked(invoke);

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

  beforeEach(() => {
    config = {
      baseUrl: 'http://localhost:8000',
      apiKey: 'test-api-key',
      timeout: 5000,
      retryAttempts: 2,
      retryDelay: 500,
    };
    service = new BowongTextVideoAgentFastApiService(config);
    vi.clearAllMocks();
  });

  afterEach(() => {
    resetDefaultService();
  });

  describe('构造函数和配置', () => {
    it('应该正确初始化服务配置', () => {
      const serviceConfig = service.getConfig();
      expect(serviceConfig).toEqual(config);
    });

    it('应该使用默认配置填充缺失的配置项', () => {
      const minimalConfig = { baseUrl: 'http://localhost:8000' };
      const serviceWithDefaults = new BowongTextVideoAgentFastApiService(minimalConfig);
      const resultConfig = serviceWithDefaults.getConfig();
      
      expect(resultConfig.timeout).toBe(30000);
      expect(resultConfig.retryAttempts).toBe(3);
      expect(resultConfig.retryDelay).toBe(1000);
    });

    it('应该能够更新配置', () => {
      const newConfig = { timeout: 10000, apiKey: 'new-key' };
      service.updateConfig(newConfig);
      
      const updatedConfig = service.getConfig();
      expect(updatedConfig.timeout).toBe(10000);
      expect(updatedConfig.apiKey).toBe('new-key');
      expect(updatedConfig.baseUrl).toBe(config.baseUrl); // 保持原有配置
    });
  });

  describe('工厂函数和单例模式', () => {
    it('createBowongTextVideoAgentService 应该创建新实例', () => {
      const newService = createBowongTextVideoAgentService(config);
      expect(newService).toBeInstanceOf(BowongTextVideoAgentFastApiService);
      expect(newService).not.toBe(service);
    });

    it('默认服务实例应该正确工作', () => {
      initializeDefaultService(config);
      const defaultService = getDefaultBowongTextVideoAgentService();
      expect(defaultService).toBeInstanceOf(BowongTextVideoAgentFastApiService);
    });

    it('未初始化时获取默认服务应该抛出错误', () => {
      expect(() => getDefaultBowongTextVideoAgentService()).toThrow('默认服务实例未初始化');
    });
  });

  describe('API 调用和错误处理', () => {
    it('成功的 API 调用应该返回结果', async () => {
      const mockResponse = { status: true, msg: 'success', data: 'test-data' };
      mockInvoke.mockResolvedValueOnce(mockResponse);

      const result = await service.getSamplePrompt();
      expect(result).toEqual(mockResponse);
      expect(mockInvoke).toHaveBeenCalledWith('get_sample_prompt', undefined);
    });

    it('API 调用失败时应该抛出适当的错误', async () => {
      const mockError = new Error('Network error');
      mockInvoke.mockRejectedValueOnce(mockError);

      await expect(service.getSamplePrompt()).rejects.toThrow();
    });

    it('应该正确处理验证错误', async () => {
      const validationError = {
        statusCode: 422,
        message: '验证失败',
        details: { detail: [{ loc: ['prompt'], msg: 'required', type: 'missing' }] }
      };
      mockInvoke.mockRejectedValueOnce(validationError);

      await expect(service.checkPrompt({ prompt: '' })).rejects.toThrow(ValidationError);
    });

    it('应该实现重试机制', async () => {
      const networkError = new Error('网络连接失败');
      const successResponse = { status: true, msg: 'success' };
      
      mockInvoke
        .mockRejectedValueOnce(networkError)
        .mockResolvedValueOnce(successResponse);

      const result = await service.checkPromptHealth();
      expect(result).toEqual(successResponse);
      expect(mockInvoke).toHaveBeenCalledTimes(2);
    });
  });

  describe('提示词预处理模块', () => {
    it('getSamplePrompt 应该正确调用 API', async () => {
      const mockResponse = { examples: ['example1', 'example2'] };
      mockInvoke.mockResolvedValueOnce(mockResponse);

      const params = { task_type: 'video' };
      const result = await service.getSamplePrompt(params);

      expect(result).toEqual(mockResponse);
      expect(mockInvoke).toHaveBeenCalledWith('get_sample_prompt', { params });
    });

    it('checkPromptHealth 应该正确调用健康检查', async () => {
      const mockResponse = { status: true, msg: 'healthy' };
      mockInvoke.mockResolvedValueOnce(mockResponse);

      const result = await service.checkPromptHealth();
      expect(result).toEqual(mockResponse);
      expect(mockInvoke).toHaveBeenCalledWith('check_prompt_health', undefined);
    });
  });

  describe('文件操作模块', () => {
    it('uploadFile 应该正确上传文件', async () => {
      const mockFile = new File(['test'], 'test.txt', { type: 'text/plain' });
      const mockResponse = { status: true, msg: 'uploaded', data: 'file-url' };
      mockInvoke.mockResolvedValueOnce(mockResponse);

      const result = await service.uploadFile({ file: mockFile });
      expect(result).toEqual(mockResponse);
    });

    it('uploadFileToS3 应该正确上传到 S3', async () => {
      const mockFile = new File(['test'], 'test.txt', { type: 'text/plain' });
      const mockResponse = { status: true, msg: 'uploaded to s3', data: 's3-url' };
      mockInvoke.mockResolvedValueOnce(mockResponse);

      const result = await service.uploadFileToS3({ file: mockFile });
      expect(result).toEqual(mockResponse);
    });
  });

  describe('视频模板管理模块', () => {
    it('getTemplates 应该返回模板列表', async () => {
      const mockResponse = {
        status: true,
        data: [{ id: '1', prompt: 'test', title_zh: '测试' }],
        page: 1,
        page_size: 10,
        total: 1,
        total_pages: 1,
      };
      mockInvoke.mockResolvedValueOnce(mockResponse);

      const result = await service.getTemplates({ page: 1, page_size: 10 });
      expect(result).toEqual(mockResponse);
    });

    it('createTemplate 应该创建新模板', async () => {
      const templateData = {
        prompt: 'test prompt',
        cover_url: 'cover.jpg',
        video_url: 'video.mp4',
        description: 'test',
        detailDescription: 'detailed test',
        title_zh: '测试模板',
        aspect_ratio: '16:9',
        engine: 'test-engine',
        presetPrompts: 'preset',
        task_type: 'video',
      };
      const mockResponse = { status: true, msg: 'created', data: { id: '1', ...templateData } };
      mockInvoke.mockResolvedValueOnce(mockResponse);

      const result = await service.createTemplate(templateData);
      expect(result).toEqual(mockResponse);
    });
  });

  describe('任务轮询机制', () => {
    it('syncGenerateImage 应该正确轮询任务状态', async () => {
      const taskId = 'test-task-id';
      const taskResponse = { task_id: taskId, status: TaskStatus.PENDING };
      const finalStatus = {
        task_id: taskId,
        status: TaskStatus.SUCCESS,
        result: { images: ['image1.jpg', 'image2.jpg'] },
      };

      mockInvoke
        .mockResolvedValueOnce(taskResponse) // asyncGenerateImage
        .mockResolvedValueOnce({ ...finalStatus, status: TaskStatus.RUNNING }) // 第一次查询
        .mockResolvedValueOnce(finalStatus); // 第二次查询

      const result = await service.syncGenerateImage({
        prompt: 'test prompt',
        max_wait_time: 10,
        poll_interval: 0.1,
      });

      expect(result.status).toBe(TaskStatus.SUCCESS);
      expect(result.images).toEqual(['image1.jpg', 'image2.jpg']);
      expect(mockInvoke).toHaveBeenCalledTimes(3);
    });

    it('任务失败时应该抛出 TaskFailedError', async () => {
      const taskId = 'failed-task-id';
      const taskResponse = { task_id: taskId, status: TaskStatus.PENDING };
      const failedStatus = {
        task_id: taskId,
        status: TaskStatus.FAILED,
        error: 'Task failed',
      };

      mockInvoke
        .mockResolvedValueOnce(taskResponse)
        .mockResolvedValueOnce(failedStatus);

      await expect(service.syncGenerateImage({
        prompt: 'test prompt',
        max_wait_time: 10,
        poll_interval: 0.1,
      })).rejects.toThrow(TaskFailedError);
    });
  });

  describe('批量操作', () => {
    it('batchQueryTaskStatus 应该查询多个任务状态', async () => {
      const taskIds = ['task1', 'task2', 'task3'];
      const mockStatuses = taskIds.map(id => ({
        task_id: id,
        status: TaskStatus.SUCCESS,
      }));

      mockInvoke
        .mockResolvedValueOnce(mockStatuses[0])
        .mockResolvedValueOnce(mockStatuses[1])
        .mockResolvedValueOnce(mockStatuses[2]);

      const results = await service.batchQueryTaskStatus(taskIds);
      expect(results).toHaveLength(3);
      expect(results.map(r => r.task_id)).toEqual(taskIds);
    });

    it('cancelTasks 应该取消多个任务', async () => {
      const taskIds = ['task1', 'task2'];
      const mockResponses = [
        { status: true, msg: 'cancelled' },
        { status: true, msg: 'cancelled' },
      ];

      mockInvoke
        .mockResolvedValueOnce(mockResponses[0])
        .mockResolvedValueOnce(mockResponses[1]);

      const results = await service.cancelTasks(taskIds);
      expect(results).toHaveLength(2);
      expect(results.every(r => r.status)).toBe(true);
    });
  });

  describe('连接测试', () => {
    it('testConnection 成功时应该返回 true', async () => {
      mockInvoke
        .mockResolvedValueOnce({ status: true, msg: 'healthy' }) // checkPromptHealth
        .mockResolvedValueOnce({ status: true, msg: 'healthy' }); // checkFileHealth

      const result = await service.testConnection();
      expect(result).toBe(true);
    });

    it('testConnection 失败时应该返回 false', async () => {
      mockInvoke.mockRejectedValueOnce(new Error('Connection failed'));

      const result = await service.testConnection();
      expect(result).toBe(false);
    });
  });
});
