import { GetPlanHandler } from '../queries/get-plan/get-plan.handler';
import { GetPlanQuery } from '../queries/get-plan/get-plan.query';

describe('GetPlanHandler', () => {
  let handler: GetPlanHandler;
  let mockPrisma: any;

  const mockPlan = {
    id: 'plan-1',
    tier: 'AGENT_PRO',
    name: 'Agent Pro',
    priceMonthlyVND: 299000n,
    priceYearlyVND: 2990000n,
    maxListings: 50,
    maxSavedSearches: 10,
    features: { analytics: true },
    isActive: true,
  };

  let mockCacheService: any;

  beforeEach(() => {
    mockPrisma = {
      plan: {
        findFirst: vi.fn(),
        findMany: vi.fn(),
      },
    };

    mockCacheService = {
      getOrSet: vi.fn((_key: string, loader: () => Promise<any>) => loader()),
    };

    handler = new GetPlanHandler(mockPrisma, mockCacheService);
  });

  it('returns a single plan by tier', async () => {
    mockPrisma.plan.findFirst.mockResolvedValue(mockPlan);

    const query = new GetPlanQuery('AGENT_PRO');
    const result = await handler.execute(query);

    expect(result).not.toBeInstanceOf(Array);
    const plan = result as any;
    expect(plan.tier).toBe('AGENT_PRO');
    expect(plan.priceMonthlyVND).toBe('299000');
    expect(plan.priceYearlyVND).toBe('2990000');
  });

  it('returns all active plans when no tier specified', async () => {
    mockPrisma.plan.findMany.mockResolvedValue([mockPlan]);

    const query = new GetPlanQuery();
    const result = await handler.execute(query);

    expect(Array.isArray(result)).toBe(true);
    expect((result as any[]).length).toBe(1);
  });

  it('throws NotFoundException when plan not found', async () => {
    mockPrisma.plan.findFirst.mockResolvedValue(null);

    const query = new GetPlanQuery('ENTERPRISE');

    await expect(handler.execute(query)).rejects.toThrow('Plan');
  });
});
