import { describe, it, expect, beforeEach, vi } from 'vitest';
import { todoManager } from '../../../../src/tools/todo/todo-manager.js';
import type { SessionManager } from '../../../../src/session/index.js';
import type { Todo } from '../../../../src/session/types.js';

describe('TodoManager', () => {
  let mockSessionManager: SessionManager;
  let mockTodos: Todo[];

  beforeEach(() => {
    mockTodos = [];
    mockSessionManager = {
      getTodos: vi.fn(() => mockTodos),
      setTodos: vi.fn(async (todos: Todo[]) => {
        mockTodos = todos;
      }),
    } as unknown as SessionManager;

    // 重置 todoManager 状态
    todoManager.setSessionManager(mockSessionManager);
  });

  describe('setSessionManager', () => {
    it('设置会话管理器后 isInitialized 返回 true', () => {
      const freshManager = {
        getTodos: vi.fn(() => []),
        setTodos: vi.fn(),
      } as unknown as SessionManager;

      todoManager.setSessionManager(freshManager);
      expect(todoManager.isInitialized()).toBe(true);
    });
  });

  describe('getTodos', () => {
    it('返回空数组当没有 todo', () => {
      const todos = todoManager.getTodos();
      expect(todos).toEqual([]);
    });

    it('返回现有的 todo 列表', () => {
      mockTodos = [
        { id: '1', content: 'Task 1', status: 'pending', createdAt: '', updatedAt: '' },
        { id: '2', content: 'Task 2', status: 'completed', createdAt: '', updatedAt: '' },
      ];

      const todos = todoManager.getTodos();
      expect(todos).toHaveLength(2);
      expect(todos[0].content).toBe('Task 1');
      expect(todos[1].content).toBe('Task 2');
    });

    it('正确调用 sessionManager.getTodos', () => {
      todoManager.getTodos();
      expect(mockSessionManager.getTodos).toHaveBeenCalled();
    });
  });

  describe('setTodos', () => {
    it('更新 todo 列表', async () => {
      const newTodos: Todo[] = [
        { id: '1', content: 'New Task', status: 'pending', createdAt: '', updatedAt: '' },
      ];

      await todoManager.setTodos(newTodos);

      expect(mockSessionManager.setTodos).toHaveBeenCalledWith(newTodos);
      expect(mockTodos).toHaveLength(1);
    });

    it('可以设置空列表', async () => {
      mockTodos = [
        { id: '1', content: 'Task', status: 'pending', createdAt: '', updatedAt: '' },
      ];

      await todoManager.setTodos([]);

      expect(mockTodos).toHaveLength(0);
    });
  });

  describe('addTodo', () => {
    it('添加新的 todo（默认状态 pending）', async () => {
      const todo = await todoManager.addTodo('新任务');

      expect(todo.content).toBe('新任务');
      expect(todo.status).toBe('pending');
      expect(todo.id).toBeDefined();
      expect(todo.createdAt).toBeDefined();
      expect(todo.updatedAt).toBeDefined();
      expect(mockTodos).toHaveLength(1);
    });

    it('添加指定状态的 todo', async () => {
      const todo = await todoManager.addTodo('进行中的任务', 'in_progress');

      expect(todo.content).toBe('进行中的任务');
      expect(todo.status).toBe('in_progress');
    });

    it('添加已完成状态的 todo', async () => {
      const todo = await todoManager.addTodo('已完成任务', 'completed');

      expect(todo.status).toBe('completed');
    });

    it('生成唯一 ID', async () => {
      const todo1 = await todoManager.addTodo('Task 1');
      const todo2 = await todoManager.addTodo('Task 2');

      expect(todo1.id).not.toBe(todo2.id);
    });

    it('追加到现有列表', async () => {
      mockTodos = [
        { id: 'existing', content: 'Existing', status: 'pending', createdAt: '', updatedAt: '' },
      ];

      await todoManager.addTodo('New Task');

      expect(mockTodos).toHaveLength(2);
      expect(mockTodos[0].content).toBe('Existing');
      expect(mockTodos[1].content).toBe('New Task');
    });
  });

  describe('updateTodoStatus', () => {
    beforeEach(() => {
      mockTodos = [
        { id: 'todo-1', content: 'Task 1', status: 'pending', createdAt: '2024-01-01', updatedAt: '2024-01-01' },
        { id: 'todo-2', content: 'Task 2', status: 'pending', createdAt: '2024-01-01', updatedAt: '2024-01-01' },
      ];
    });

    it('更新存在的 todo 状态', async () => {
      const result = await todoManager.updateTodoStatus('todo-1', 'completed');

      expect(result).toBe(true);
      expect(mockTodos[0].status).toBe('completed');
    });

    it('更新 updatedAt 时间戳', async () => {
      const originalUpdatedAt = mockTodos[0].updatedAt;

      await todoManager.updateTodoStatus('todo-1', 'in_progress');

      expect(mockTodos[0].updatedAt).not.toBe(originalUpdatedAt);
    });

    it('不存在的 todo 返回 false', async () => {
      const result = await todoManager.updateTodoStatus('non-existent', 'completed');

      expect(result).toBe(false);
    });

    it('可以更新为任意状态', async () => {
      await todoManager.updateTodoStatus('todo-1', 'in_progress');
      expect(mockTodos[0].status).toBe('in_progress');

      await todoManager.updateTodoStatus('todo-1', 'completed');
      expect(mockTodos[0].status).toBe('completed');

      await todoManager.updateTodoStatus('todo-1', 'pending');
      expect(mockTodos[0].status).toBe('pending');
    });
  });

  describe('deleteTodo', () => {
    beforeEach(() => {
      mockTodos = [
        { id: 'todo-1', content: 'Task 1', status: 'pending', createdAt: '', updatedAt: '' },
        { id: 'todo-2', content: 'Task 2', status: 'completed', createdAt: '', updatedAt: '' },
        { id: 'todo-3', content: 'Task 3', status: 'in_progress', createdAt: '', updatedAt: '' },
      ];
    });

    it('删除存在的 todo', async () => {
      const result = await todoManager.deleteTodo('todo-2');

      expect(result).toBe(true);
      expect(mockTodos).toHaveLength(2);
      expect(mockTodos.find(t => t.id === 'todo-2')).toBeUndefined();
    });

    it('删除第一个 todo', async () => {
      const result = await todoManager.deleteTodo('todo-1');

      expect(result).toBe(true);
      expect(mockTodos[0].id).toBe('todo-2');
    });

    it('删除最后一个 todo', async () => {
      const result = await todoManager.deleteTodo('todo-3');

      expect(result).toBe(true);
      expect(mockTodos).toHaveLength(2);
    });

    it('不存在的 todo 返回 false', async () => {
      const result = await todoManager.deleteTodo('non-existent');

      expect(result).toBe(false);
      expect(mockTodos).toHaveLength(3);
    });

    it('删除后其他 todo 保持不变', async () => {
      await todoManager.deleteTodo('todo-2');

      expect(mockTodos[0].content).toBe('Task 1');
      expect(mockTodos[1].content).toBe('Task 3');
    });
  });

  describe('clearTodos', () => {
    it('清空所有 todo', async () => {
      mockTodos = [
        { id: '1', content: 'Task 1', status: 'pending', createdAt: '', updatedAt: '' },
        { id: '2', content: 'Task 2', status: 'completed', createdAt: '', updatedAt: '' },
      ];

      await todoManager.clearTodos();

      expect(mockTodos).toHaveLength(0);
      expect(mockSessionManager.setTodos).toHaveBeenCalledWith([]);
    });

    it('空列表时调用也不报错', async () => {
      mockTodos = [];

      await expect(todoManager.clearTodos()).resolves.not.toThrow();
      expect(mockTodos).toHaveLength(0);
    });
  });

  describe('isInitialized', () => {
    it('初始化后返回 true', () => {
      expect(todoManager.isInitialized()).toBe(true);
    });
  });

  describe('边界情况', () => {
    it('处理包含特殊字符的 content', async () => {
      const specialContent = '任务: "测试" & <script>alert(1)</script>';
      const todo = await todoManager.addTodo(specialContent);

      expect(todo.content).toBe(specialContent);
    });

    it('处理非常长的 content', async () => {
      const longContent = 'A'.repeat(10000);
      const todo = await todoManager.addTodo(longContent);

      expect(todo.content).toBe(longContent);
    });

    it('处理空字符串 content', async () => {
      const todo = await todoManager.addTodo('');

      expect(todo.content).toBe('');
    });

    it('连续操作保持数据一致性', async () => {
      await todoManager.addTodo('Task 1');
      await todoManager.addTodo('Task 2');
      await todoManager.updateTodoStatus(mockTodos[0].id, 'completed');
      await todoManager.deleteTodo(mockTodos[1].id);
      await todoManager.addTodo('Task 3');

      expect(mockTodos).toHaveLength(2);
      expect(mockTodos[0].status).toBe('completed');
      expect(mockTodos[1].content).toBe('Task 3');
    });
  });
});
