import { Test, TestingModule } from '@nestjs/testing';
import { AffiliateService } from '../affiliate.service';
import { NotFoundException } from '@nestjs/common';

const mockPrisma: any = {
  affiliateClick: {
    groupBy: jest.fn(),
    create: jest.fn(),
  },
  affiliateLink: {
    findMany: jest.fn(),
    findUnique: jest.fn(),
  },
  affiliateProgram: { findMany: jest.fn() },
  user: { findUnique: jest.fn() },
};

describe('AffiliateService', () => {
  let service: AffiliateService;

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      providers: [{ provide: AffiliateService, useValue: new AffiliateService(mockPrisma) }],
    }).compile();
    service = module.get(AffiliateService);
    jest.clearAllMocks();
  });

  it('getStats 聚合点击量与预估收益', async () => {
    mockPrisma.affiliateClick.groupBy.mockResolvedValue([{ linkId: 1, _count: { _all: 10 } }]);
    mockPrisma.affiliateLink.findMany.mockResolvedValue([
      { id: 1, title: '豆包', estimatedCommission: 0.5 },
    ]);

    const result = await service.getStats();
    expect(result.totalClicks).toBe(10);
    expect(result.totalRevenue).toBe(5);
    expect(result.topLinks[0].title).toBe('豆包');
  });

  it('trackClick 记录点击并返回跳转地址', async () => {
    mockPrisma.affiliateLink.findUnique.mockResolvedValue({
      id: 1,
      url: 'https://example.com',
      active: true,
    });
    mockPrisma.affiliateClick.create.mockResolvedValue({});

    const res = await service.trackClick(1, '42', '1.2.3.4');
    expect(res.redirectUrl).toBe('https://example.com');
    expect(mockPrisma.affiliateClick.create).toHaveBeenCalledWith({
      data: { linkId: 1, userId: 42, ip: '1.2.3.4' },
    });
  });

  it('trackClick 在链接不存在时抛 NotFound', async () => {
    mockPrisma.affiliateLink.findUnique.mockResolvedValue(null);
    await expect(service.trackClick(99)).rejects.toBeInstanceOf(NotFoundException);
  });

  it('getLinks 透传 skillId/toolId 过滤', async () => {
    mockPrisma.affiliateLink.findMany.mockResolvedValue([{ id: 2, title: '工具' }]);
    const res = await service.getLinks({ skillId: 'title-craft', toolId: 5, featured: true });
    expect(res.links).toHaveLength(1);
    expect(mockPrisma.affiliateLink.findMany).toHaveBeenCalledWith(
      expect.objectContaining({
        where: { active: true, skillId: 'title-craft', toolId: 5, isFeatured: true },
      }),
    );
  });
});
