// src/routes/admin.system.routes.test.ts
import { describe, it, expect, vi, beforeEach } from 'vitest';
import supertest from 'supertest';
import { Request, Response, NextFunction } from 'express';
import adminRouter from './admin.routes';
import { createMockUserProfile } from '../tests/utils/mockFactories';
import { createTestApp } from '../tests/utils/createTestApp';

// Mock dependencies
vi.mock('../services/geocodingService.server', () => ({
  geocodingService: {
    clearGeocodeCache: vi.fn(),
  },
}));

// Mock other dependencies that are part of the adminRouter setup but not directly tested here
vi.mock('../services/db/index.db', () => ({
  adminRepo: {},
  flyerRepo: {},
  recipeRepo: {},
  userRepo: {},
  personalizationRepo: {},
  notificationRepo: {},
}));
vi.mock('../services/db/flyer.db');
vi.mock('../services/db/recipe.db');
vi.mock('../services/db/user.db');
vi.mock('node:fs/promises');
vi.mock('../services/backgroundJobService', () => ({
  backgroundJobService: {
    runDailyDealCheck: vi.fn(),
  },
}));
vi.mock('../services/queueService.server');
vi.mock('@bull-board/api');
vi.mock('@bull-board/api/bullMQAdapter');
vi.mock('@bull-board/express', () => ({
  ExpressAdapter: class {
    setBasePath = vi.fn();
    getRouter = vi.fn().mockReturnValue((req: Request, res: Response, next: NextFunction) => next());
  },
}));

// Import the mocked modules to control them
import { geocodingService } from '../services/geocodingService.server';

// Mock the logger
vi.mock('../services/logger.server', () => ({
  logger: { info: vi.fn(), debug: vi.fn(), error: vi.fn(), warn: vi.fn() },
}));

// Mock the passport middleware
vi.mock('./passport.routes', () => ({
  default: {
    authenticate: vi.fn(() => (req: Request, res: Response, next: NextFunction) => {
      req.user = createMockUserProfile({ role: 'admin' });
      next();
    }),
  },
  isAdmin: (req: Request, res: Response, next: NextFunction) => next(),
}));

describe('Admin System Routes (/api/admin/system)', () => {
  const adminUser = createMockUserProfile({ role: 'admin' });
  const app = createTestApp({ router: adminRouter, basePath: '/api/admin', authenticatedUser: adminUser });

  // Add a basic error handler to capture errors passed to next(err) and return JSON.
  // This prevents unhandled error crashes in tests and ensures we get the 500 response we expect.
  app.use((err: any, req: any, res: any, next: any) => {
    res.status(err.status || 500).json({ message: err.message, errors: err.errors });
  });

  beforeEach(() => {
    vi.clearAllMocks();
  });

  describe('POST /system/clear-geocode-cache', () => {
    it('should return 200 on successful cache clear', async () => {
      vi.mocked(geocodingService.clearGeocodeCache).mockResolvedValue(10);
      const response = await supertest(app).post('/api/admin/system/clear-geocode-cache');
      expect(response.status).toBe(200);
      expect(response.body.message).toContain('10 keys were removed');
    });

    it('should return 500 if clearing the cache fails', async () => {
      vi.mocked(geocodingService.clearGeocodeCache).mockRejectedValue(new Error('Redis is down'));
      const response = await supertest(app).post('/api/admin/system/clear-geocode-cache');
      expect(response.status).toBe(500);
      expect(response.body.message).toContain('Redis is down');
    });
  });
});