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

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

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

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

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

  describe('findAll', () => {
    it('should return paginated prompts with default params', async () => {
      const mockPrompts = [
        { id: 1, title: '提示词1', status: 'PUBLISHED', deletedAt: null, isPublic: true },
      ];
      mockPrisma.prompt.findMany.mockResolvedValue(mockPrompts);
      mockPrisma.prompt.count.mockResolvedValue(1);

      const result = await service.findAll({});

      expect(result).toEqual({ items: mockPrompts, total: 1, page: 1, pageSize: 20 });
      expect(mockPrisma.prompt.findMany).toHaveBeenCalledWith(
        expect.objectContaining({
          where: { status: 'PUBLISHED', deletedAt: null, isPublic: true },
          skip: 0,
          take: 20,
        })
      );
    });

    it('should filter by categoryId', async () => {
      await service.findAll({ categoryId: 5 });
      expect(mockPrisma.prompt.findMany).toHaveBeenCalledWith(
        expect.objectContaining({
          where: expect.objectContaining({ categoryId: 5 }),
        })
      );
    });

    it('should search by keyword', async () => {
      await service.findAll({ search: 'AI' });
      expect(mockPrisma.prompt.findMany).toHaveBeenCalledWith(
        expect.objectContaining({
          where: expect.objectContaining({
            OR: [{ title: { contains: 'AI' } }, { content: { contains: 'AI' } }],
          }),
        })
      );
    });
  });

  describe('findById', () => {
    it('should increment viewCount and return prompt', async () => {
      const mockPrompt = { id: 1, title: '测试提示词', viewCount: 10 };
      mockPrisma.prompt.findUnique.mockResolvedValue(mockPrompt);

      const result = await service.findById(1);
      
      expect(result).toEqual(mockPrompt);
      expect(mockPrisma.prompt.update).toHaveBeenCalledWith({
        where: { id: 1 },
        data: { viewCount: { increment: 1 } },
      });
    });
  });

  describe('create', () => {
    it('should create a new prompt', async () => {
      const promptData = {
        title: '新提示词',
        content: '内容',
        description: '描述',
        categoryId: 1,
        tags: 'AI,提示词',
        model: 'gpt-3.5',
        authorId: 1,
      };
      const created = { id: 1, ...promptData };
      mockPrisma.prompt.create.mockResolvedValue(created);

      const result = await service.create(promptData);
      
      expect(result).toEqual(created);
      expect(mockPrisma.prompt.create).toHaveBeenCalledWith({ data: promptData });
    });
  });

  describe('toggleFavorite', () => {
    it('should add favorite if not exists', async () => {
      mockPrisma.promptFavorite.findUnique.mockResolvedValue(null);
      mockPrisma.promptFavorite.create.mockResolvedValue({});
      mockPrisma.prompt.update.mockResolvedValue({});

      const result = await service.toggleFavorite(1, 1);
      
      expect(result).toEqual({ favorited: true });
      expect(mockPrisma.promptFavorite.create).toHaveBeenCalledWith({
        data: { userId: 1, promptId: 1 },
      });
      expect(mockPrisma.prompt.update).toHaveBeenCalledWith({
        where: { id: 1 },
        data: { likeCount: { increment: 1 } },
      });
    });

    it('should remove favorite if exists', async () => {
      mockPrisma.promptFavorite.findUnique.mockResolvedValue({ id: 1 });
      mockPrisma.promptFavorite.delete.mockResolvedValue({});
      mockPrisma.prompt.update.mockResolvedValue({});

      const result = await service.toggleFavorite(1, 1);
      
      expect(result).toEqual({ favorited: false });
      expect(mockPrisma.promptFavorite.delete).toHaveBeenCalledWith({
        where: { id: 1 },
      });
    });
  });

  describe('findFavorites', () => {
    it('should return user favorites with pagination', async () => {
      const mockFavorites = [
        { id: 1, userId: 1, promptId: 1, prompt: { id: 1, title: '提示词1' } },
      ];
      mockPrisma.promptFavorite.findMany.mockResolvedValue(mockFavorites);
      mockPrisma.promptFavorite.count.mockResolvedValue(1);

      const result = await service.findFavorites(1, { page: 1, pageSize: 10 });
      
      expect(result).toEqual({ items: mockFavorites, total: 1, page: 1, pageSize: 10 });
    });
  });
});
