import { Test, TestingModule } from '@nestjs/testing';
import { ToolsService } from '../tools.service';
import { PrismaService } from '../../../prisma/prisma.service';

describe('ToolsService', () => {
  let service: ToolsService;
  let prisma: PrismaService;

  const mockPrisma = {
    tool: {
      findMany: jest.fn(),
      findUnique: jest.fn(),
      count: jest.fn(),
      create: jest.fn(),
      update: jest.fn(),
    },
  };

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      providers: [
        ToolsService,
        { provide: PrismaService, useValue: mockPrisma },
      ],
    }).compile();

    service = module.get<ToolsService>(ToolsService);
    prisma = module.get<PrismaService>(PrismaService);
    jest.clearAllMocks();
  });

  describe('findAll', () => {
    it('should return paginated tools', async () => {
      const mockTools = [{ id: 1, name: 'ChatGPT', slug: 'chatgpt', category: { id: 1, name: '聊天' } }];
      mockPrisma.tool.findMany.mockResolvedValue(mockTools);
      mockPrisma.tool.count.mockResolvedValue(1);

      const result = await service.findAll({ page: 1, pageSize: 20 });
      expect(result.items).toEqual(mockTools);
      expect(result.total).toBe(1);
      expect(result.page).toBe(1);
      expect(result.pageSize).toBe(20);
    });

    it('should filter by categoryId', async () => {
      mockPrisma.tool.findMany.mockResolvedValue([]);
      mockPrisma.tool.count.mockResolvedValue(0);

      await service.findAll({ categoryId: 2 });
      expect(mockPrisma.tool.findMany).toHaveBeenCalledWith(
        expect.objectContaining({
          where: expect.objectContaining({ categoryId: 2 }),
        }),
      );
    });

    it('should filter by isFeatured', async () => {
      mockPrisma.tool.findMany.mockResolvedValue([]);
      mockPrisma.tool.count.mockResolvedValue(0);

      await service.findAll({ isFeatured: true });
      expect(mockPrisma.tool.findMany).toHaveBeenCalledWith(
        expect.objectContaining({
          where: expect.objectContaining({ isFeatured: true }),
        }),
      );
    });
  });

  describe('findBySlug', () => {
    it('should return tool by slug', async () => {
      const mockTool = { id: 1, name: 'DeepSeek', slug: 'deepseek', category: { id: 1, name: '聊天' } };
      mockPrisma.tool.findUnique.mockResolvedValue(mockTool);
      mockPrisma.tool.update.mockResolvedValue(mockTool);

      const result = await service.findBySlug('deepseek');
      expect(result.name).toBe('DeepSeek');
      expect(mockPrisma.tool.findUnique).toHaveBeenCalledWith({
        where: { slug: 'deepseek' },
        include: { category: true },
      });
    });

    it('should throw on missing tool', async () => {
      mockPrisma.tool.findUnique.mockResolvedValue(null);
      await expect(service.findBySlug('nonexistent')).rejects.toThrow('工具不存在');
    });
  });

  describe('create', () => {
    it('should create a tool', async () => {
      const data = { name: 'New Tool', slug: 'new-tool', url: 'https://example.com' };
      mockPrisma.tool.create.mockResolvedValue({ id: 1, ...data });

      const result = await service.create(data);
      expect(result).toHaveProperty('id', 1);
      expect(mockPrisma.tool.create).toHaveBeenCalledWith({ data });
    });
  });
});