import { NotificationsController } from '../controllers/notifications.controller';

describe('NotificationsController', () => {
  let controller: NotificationsController;
  let mockNotificationRepo: { findByUserId: ReturnType<typeof vi.fn> };
  let mockPreferenceRepo: { findByUserId: ReturnType<typeof vi.fn>; upsert: ReturnType<typeof vi.fn> };
  let mockTemplateService: { getTemplateKeys: ReturnType<typeof vi.fn> };

  const mockUser = { sub: 'user-1', phone: '0901234567', role: 'BUYER' };

  const mockNotification = {
    id: 'notif-1',
    userId: 'user-1',
    channel: 'EMAIL' as const,
    templateKey: 'user.registered',
    subject: 'Welcome',
    body: '<p>Hello</p>',
    metadata: null,
    status: 'SENT' as const,
    errorDetail: null,
    sentAt: new Date(),
    createdAt: new Date(),
  };

  const mockPreference = {
    id: 'pref-1',
    userId: 'user-1',
    channel: 'EMAIL' as const,
    eventType: 'user.registered',
    enabled: true,
    createdAt: new Date(),
    updatedAt: new Date(),
  };

  beforeEach(() => {
    mockNotificationRepo = { findByUserId: vi.fn() };
    mockPreferenceRepo = { findByUserId: vi.fn(), upsert: vi.fn() };
    mockTemplateService = { getTemplateKeys: vi.fn() };

    controller = new NotificationsController(
      mockNotificationRepo as any,
      mockPreferenceRepo as any,
      mockTemplateService as any,
    );
  });

  it('getHistory calls notificationRepo.findByUserId with user sub and default limit', async () => {
    mockNotificationRepo.findByUserId.mockResolvedValue([mockNotification]);

    const result = await controller.getHistory(mockUser as any, undefined);

    expect(mockNotificationRepo.findByUserId).toHaveBeenCalledWith('user-1', 50);
    expect(result).toEqual([mockNotification]);
  });

  it('getHistory passes custom limit', async () => {
    mockNotificationRepo.findByUserId.mockResolvedValue([mockNotification]);

    await controller.getHistory(mockUser as any, 10);

    expect(mockNotificationRepo.findByUserId).toHaveBeenCalledWith('user-1', 10);
  });

  it('getPreferences calls preferenceRepo.findByUserId', async () => {
    mockPreferenceRepo.findByUserId.mockResolvedValue([mockPreference]);

    const result = await controller.getPreferences(mockUser as any);

    expect(mockPreferenceRepo.findByUserId).toHaveBeenCalledWith('user-1');
    expect(result).toEqual([mockPreference]);
  });

  it('updatePreference calls preferenceRepo.upsert with correct params', async () => {
    mockPreferenceRepo.upsert.mockResolvedValue({ ...mockPreference, enabled: false });

    const result = await controller.updatePreference(mockUser as any, {
      channel: 'EMAIL' as any,
      eventType: 'user.registered',
      enabled: false,
    });

    expect(mockPreferenceRepo.upsert).toHaveBeenCalledWith('user-1', 'EMAIL', 'user.registered', false);
    expect(result.enabled).toBe(false);
  });

  it('getTemplates returns template keys from templateService', async () => {
    const keys = ['user.registered', 'agent.verified', 'listing.approved', 'inquiry.received', 'quota.exceeded', 'password.reset'];
    mockTemplateService.getTemplateKeys.mockReturnValue(keys);

    const result = await controller.getTemplates();

    expect(mockTemplateService.getTemplateKeys).toHaveBeenCalled();
    expect(result).toEqual({ templates: keys });
  });
});
