// Mock Taro 在导入之前
import { AsyncTaskManager, TaskStatus, TaskConfig } from '../AsyncTaskManager';

const mockTaro = {
  request: jest.fn(),
  setStorage: jest.fn().mockResolvedValue({}),
  getStorage: jest.fn().mockResolvedValue({ data: {} }),
  removeStorage: jest.fn().mockResolvedValue({})
};

// Mock '@tarojs/taro' 模块
jest.mock('@tarojs/taro', () => mockTaro);

describe('AsyncTaskManager', () => {
  let taskManager: AsyncTaskManager;
  
  beforeEach(() => {
    jest.clearAllMocks();
    jest.useFakeTimers();
    // 确保 mock 函数正确重置
    mockTaro.setStorage.mockResolvedValue({});
    mockTaro.getStorage.mockResolvedValue({ data: {} });
    
    // 注入 storage mock
    taskManager = new AsyncTaskManager(mockTaro);
  });

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

  describe('任务提交和状态管理', () => {
    it('应该能创建新任务', async () => {
      const config: TaskConfig = {
        taskId: 'test-task-001',
        pollingInterval: 2000,
        maxRetries: 3,
        timeout: 60000
      };

      await taskManager.startTask(config);
      
      expect(taskManager.hasTask('test-task-001')).toBe(true);
      expect(taskManager.getTaskStatus('test-task-001')).toBe(TaskStatus.RUNNING);
    });

    it('应该能获取任务状态', async () => {
      const config: TaskConfig = {
        taskId: 'test-task-002',
        pollingInterval: 1000,
        maxRetries: 2,
        timeout: 30000
      };

      await taskManager.startTask(config);
      
      const status = taskManager.getTaskStatus('test-task-002');
      expect(status).toBe(TaskStatus.RUNNING);
    });

    it('应该能取消正在运行的任务', async () => {
      const config: TaskConfig = {
        taskId: 'test-task-003',
        pollingInterval: 2000,
        maxRetries: 3,
        timeout: 60000
      };

      await taskManager.startTask(config);
      await taskManager.cancelTask('test-task-003');
      
      expect(taskManager.getTaskStatus('test-task-003')).toBe(TaskStatus.CANCELLED);
    });
  });

  describe('轮询机制', () => {
    it('应该开始轮询任务状态', async () => {
      const mockStatusCheck = jest.fn().mockResolvedValue(TaskStatus.RUNNING);
      taskManager.setStatusChecker(mockStatusCheck);
      
      const config: TaskConfig = {
        taskId: 'test-poll-001',
        pollingInterval: 1000,
        maxRetries: 3,
        timeout: 60000
      };

      await taskManager.startTask(config);
      
      // 快进1秒触发轮询
      jest.advanceTimersByTime(1000);
      await Promise.resolve(); // 等待异步操作
      
      expect(mockStatusCheck).toHaveBeenCalledWith('test-poll-001');
    });

    it('应该在任务完成时停止轮询', async () => {
      const mockStatusCheck = jest.fn()
        .mockResolvedValueOnce(TaskStatus.RUNNING)
        .mockResolvedValueOnce(TaskStatus.SUCCESS);
      
      taskManager.setStatusChecker(mockStatusCheck);
      
      const config: TaskConfig = {
        taskId: 'test-poll-002',
        pollingInterval: 1000,
        maxRetries: 3,
        timeout: 60000
      };

      await taskManager.startTask(config);
      
      // 触发两次轮询
      jest.advanceTimersByTime(1000);
      await Promise.resolve();
      jest.advanceTimersByTime(1000);
      await Promise.resolve();
      
      expect(taskManager.getTaskStatus('test-poll-002')).toBe(TaskStatus.SUCCESS);
    });
  });

  describe('回调处理', () => {
    it('应该在任务成功时调用成功回调', async () => {
      const onSuccess = jest.fn();
      const mockStatusCheck = jest.fn().mockResolvedValue(TaskStatus.SUCCESS);
      taskManager.setStatusChecker(mockStatusCheck);
      
      const config: TaskConfig = {
        taskId: 'test-callback-001',
        pollingInterval: 1000,
        maxRetries: 3,
        timeout: 60000,
        onSuccess
      };

      await taskManager.startTask(config);
      
      jest.advanceTimersByTime(1000);
      await Promise.resolve();
      
      expect(onSuccess).toHaveBeenCalled();
    });

    it('应该在任务失败时调用错误回调', async () => {
      const onError = jest.fn();
      const mockStatusCheck = jest.fn().mockResolvedValue(TaskStatus.FAILED);
      taskManager.setStatusChecker(mockStatusCheck);
      
      const config: TaskConfig = {
        taskId: 'test-callback-002',
        pollingInterval: 1000,
        maxRetries: 3,
        timeout: 60000,
        onError
      };

      await taskManager.startTask(config);
      
      jest.advanceTimersByTime(1000);
      await Promise.resolve();
      
      expect(onError).toHaveBeenCalled();
    });

    it('应该在进度更新时调用进度回调', async () => {
      const onProgress = jest.fn();
      const mockStatusCheck = jest.fn().mockResolvedValue(TaskStatus.RUNNING);
      taskManager.setStatusChecker(mockStatusCheck);
      
      const config: TaskConfig = {
        taskId: 'test-callback-003',
        pollingInterval: 1000,
        maxRetries: 3,
        timeout: 60000,
        onProgress
      };

      await taskManager.startTask(config);
      
      jest.advanceTimersByTime(1000);
      await Promise.resolve();
      
      expect(onProgress).toHaveBeenCalledWith(TaskStatus.RUNNING);
    });
  });

  describe('超时处理', () => {
    it('应该在超时后将任务标记为超时状态', async () => {
      const onTimeout = jest.fn();
      const mockStatusCheck = jest.fn().mockResolvedValue(TaskStatus.RUNNING);
      taskManager.setStatusChecker(mockStatusCheck);
      
      const config: TaskConfig = {
        taskId: 'test-timeout-001',
        pollingInterval: 100,
        maxRetries: 3,
        timeout: 150, // 150毫秒超时
        onTimeout
      };

      await taskManager.startTask(config);
      
      // 快进到第一次轮询时间
      jest.advanceTimersByTime(100);
      await Promise.resolve();
      
      // 再快进到超时时间
      jest.advanceTimersByTime(100);
      await Promise.resolve();
      
      expect(taskManager.getTaskStatus('test-timeout-001')).toBe(TaskStatus.TIMEOUT);
      expect(onTimeout).toHaveBeenCalled();
    }, 2000); // 2秒超时限制
  });

  describe('持久化存储', () => {
    it('应该将任务状态保存到本地存储', async () => {
      const config: TaskConfig = {
        taskId: 'test-storage-001',
        pollingInterval: 2000,
        maxRetries: 3,
        timeout: 60000
      };

      await taskManager.startTask(config);
      
      expect(mockTaro.setStorage).toHaveBeenCalledWith({
        key: 'async_tasks',
        data: expect.objectContaining({
          'test-storage-001': expect.objectContaining({
            id: 'test-storage-001',
            status: TaskStatus.RUNNING
          })
        })
      });
    }, 2000);

    it('应该从本地存储恢复任务', async () => {
      const storedTasks = {
        'restored-task-001': {
          id: 'restored-task-001',
          status: TaskStatus.RUNNING,
          startTime: Date.now() - 10000,
          retryCount: 0,
          lastPollTime: Date.now() - 5000,
          config: {
            taskId: 'restored-task-001',
            pollingInterval: 2000,
            maxRetries: 3,
            timeout: 60000
          }
        }
      };
      
      mockTaro.getStorage.mockResolvedValueOnce({ data: storedTasks });
      
      await taskManager.resumeTasks();
      
      expect(taskManager.hasTask('restored-task-001')).toBe(true);
    });
  });

  describe('错误处理和重试', () => {
    it('应该在网络错误时进行重试', async () => {
      const mockStatusCheck = jest.fn()
        .mockRejectedValueOnce(new Error('网络错误'))
        .mockRejectedValueOnce(new Error('网络错误'))
        .mockResolvedValueOnce(TaskStatus.SUCCESS);
      
      taskManager.setStatusChecker(mockStatusCheck);
      
      const config: TaskConfig = {
        taskId: 'test-retry-001',
        pollingInterval: 1000,
        maxRetries: 3,
        timeout: 60000
      };

      await taskManager.startTask(config);
      
      // 触发多次轮询以测试重试
      for (let i = 0; i < 3; i++) {
        jest.advanceTimersByTime(1000);
        await Promise.resolve();
      }
      
      expect(mockStatusCheck).toHaveBeenCalledTimes(3);
      expect(taskManager.getTaskStatus('test-retry-001')).toBe(TaskStatus.SUCCESS);
    });

    it('应该在达到最大重试次数后标记为失败', async () => {
      const mockStatusCheck = jest.fn().mockRejectedValue(new Error('持续网络错误'));
      taskManager.setStatusChecker(mockStatusCheck);
      
      const config: TaskConfig = {
        taskId: 'test-retry-002',
        pollingInterval: 1000,
        maxRetries: 2,
        timeout: 60000
      };

      await taskManager.startTask(config);
      
      // 触发足够的轮询次数以超过重试限制
      for (let i = 0; i < 4; i++) {
        jest.advanceTimersByTime(1000);
        await Promise.resolve();
      }
      
      expect(taskManager.getTaskStatus('test-retry-002')).toBe(TaskStatus.FAILED);
    });
  });

  describe('任务暂停和恢复', () => {
    it('应该能暂停所有活跃任务的轮询', async () => {
      const config: TaskConfig = {
        taskId: 'test-pause-001',
        pollingInterval: 1000,
        maxRetries: 3,
        timeout: 60000
      };

      await taskManager.startTask(config);
      taskManager.pausePolling();
      
      const mockStatusCheck = jest.fn();
      taskManager.setStatusChecker(mockStatusCheck);
      
      // 即使时间前进，暂停状态下不应该触发轮询
      jest.advanceTimersByTime(2000);
      await Promise.resolve();
      
      expect(mockStatusCheck).not.toHaveBeenCalled();
    });

    it('应该能恢复所有任务的轮询', async () => {
      const mockStatusCheck = jest.fn().mockResolvedValue(TaskStatus.RUNNING);
      taskManager.setStatusChecker(mockStatusCheck);
      
      const config: TaskConfig = {
        taskId: 'test-resume-001',
        pollingInterval: 1000,
        maxRetries: 3,
        timeout: 60000
      };

      await taskManager.startTask(config);
      taskManager.pausePolling();
      taskManager.activatePolling();
      
      jest.advanceTimersByTime(1000);
      await Promise.resolve();
      
      expect(mockStatusCheck).toHaveBeenCalled();
    });
  });
});