/**
 * Tests unitaires pour TfsScheduler
 */

/* eslint-disable @typescript-eslint/no-explicit-any */
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
import { TfsScheduler } from '../scheduler';
import { userPreferencesService } from '@/services/core/user-preferences';
import { TfsService } from '../tfs';
import { prisma } from '@/services/core/database';
import { getToday, addMinutes } from '@/lib/date-utils';

// Mock de userPreferencesService
vi.mock('@/services/core/user-preferences', () => ({
  userPreferencesService: {
    getTfsConfig: vi.fn(),
    getTfsSchedulerConfig: vi.fn(),
  },
}));

// Mock de TfsService
vi.mock('../tfs', () => ({
  TfsService: vi.fn(),
}));

// Mock de prisma
vi.mock('@/services/core/database', () => ({
  prisma: {
    user: {
      findFirst: vi.fn(),
    },
  },
}));

// Mock de date-utils
vi.mock('@/lib/date-utils', () => ({
  getToday: vi.fn(),
  addMinutes: vi.fn(),
}));

describe('TfsScheduler', () => {
  let scheduler: TfsScheduler;
  let mockTfsService: any;

  beforeEach(() => {
    vi.clearAllMocks();
    scheduler = new TfsScheduler();
    vi.useFakeTimers();

    // Mock TfsService
    mockTfsService = {
      testConnection: vi.fn(),
      syncTasks: vi.fn(),
    };
    vi.mocked(TfsService).mockImplementation(() => mockTfsService as any);
  });

  afterEach(() => {
    scheduler.stop();
    vi.useRealTimers();
  });

  describe('start', () => {
    it('devrait démarrer le scheduler si activé et configuré', async () => {
      vi.mocked(userPreferencesService.getTfsSchedulerConfig).mockResolvedValue(
        {
          tfsAutoSync: true,
          tfsSyncInterval: 'hourly',
        } as any
      );
      vi.mocked(userPreferencesService.getTfsConfig).mockResolvedValue({
        enabled: true,
        organizationUrl: 'https://dev.azure.com/test',
        personalAccessToken: 'token123',
      } as any);

      await scheduler.start('user1');

      expect(scheduler.isActive()).toBe(true);
    });

    it('ne devrait pas démarrer si désactivé', async () => {
      vi.mocked(userPreferencesService.getTfsSchedulerConfig).mockResolvedValue(
        {
          tfsAutoSync: false,
          tfsSyncInterval: 'hourly',
        } as any
      );

      await scheduler.start('user1');

      expect(scheduler.isActive()).toBe(false);
    });

    it('ne devrait pas démarrer si TFS non configuré', async () => {
      vi.mocked(userPreferencesService.getTfsSchedulerConfig).mockResolvedValue(
        {
          tfsAutoSync: true,
          tfsSyncInterval: 'hourly',
        } as any
      );
      vi.mocked(userPreferencesService.getTfsConfig).mockResolvedValue({
        enabled: false,
      } as any);

      await scheduler.start('user1');

      expect(scheduler.isActive()).toBe(false);
    });

    it('ne devrait pas démarrer deux fois', async () => {
      vi.mocked(userPreferencesService.getTfsSchedulerConfig).mockResolvedValue(
        {
          tfsAutoSync: true,
          tfsSyncInterval: 'hourly',
        } as any
      );
      vi.mocked(userPreferencesService.getTfsConfig).mockResolvedValue({
        enabled: true,
        organizationUrl: 'https://dev.azure.com/test',
        personalAccessToken: 'token123',
      } as any);

      await scheduler.start('user1');
      const firstCall = scheduler.isActive();
      await scheduler.start('user1');
      const secondCall = scheduler.isActive();

      expect(firstCall).toBe(true);
      expect(secondCall).toBe(true);
    });
  });

  describe('stop', () => {
    it('devrait arrêter le scheduler', async () => {
      vi.mocked(userPreferencesService.getTfsSchedulerConfig).mockResolvedValue(
        {
          tfsAutoSync: true,
          tfsSyncInterval: 'hourly',
        } as any
      );
      vi.mocked(userPreferencesService.getTfsConfig).mockResolvedValue({
        enabled: true,
        organizationUrl: 'https://dev.azure.com/test',
        personalAccessToken: 'token123',
      } as any);

      await scheduler.start('user1');
      expect(scheduler.isActive()).toBe(true);

      scheduler.stop();
      expect(scheduler.isActive()).toBe(false);
    });
  });

  describe('restart', () => {
    it('devrait redémarrer le scheduler', async () => {
      vi.mocked(userPreferencesService.getTfsSchedulerConfig).mockResolvedValue(
        {
          tfsAutoSync: true,
          tfsSyncInterval: 'hourly',
        } as any
      );
      vi.mocked(userPreferencesService.getTfsConfig).mockResolvedValue({
        enabled: true,
        organizationUrl: 'https://dev.azure.com/test',
        personalAccessToken: 'token123',
      } as any);

      await scheduler.start('user1');
      expect(scheduler.isActive()).toBe(true);

      await scheduler.restart('user1');
      expect(scheduler.isActive()).toBe(true);
    });
  });

  describe('isActive', () => {
    it('devrait retourner false si pas démarré', () => {
      expect(scheduler.isActive()).toBe(false);
    });

    it('devrait retourner true si démarré', async () => {
      vi.mocked(userPreferencesService.getTfsSchedulerConfig).mockResolvedValue(
        {
          tfsAutoSync: true,
          tfsSyncInterval: 'hourly',
        } as any
      );
      vi.mocked(userPreferencesService.getTfsConfig).mockResolvedValue({
        enabled: true,
        organizationUrl: 'https://dev.azure.com/test',
        personalAccessToken: 'token123',
      } as any);

      await scheduler.start('user1');
      expect(scheduler.isActive()).toBe(true);
    });
  });

  describe('performScheduledSync', () => {
    it('devrait exécuter une synchronisation automatique', async () => {
      vi.mocked(userPreferencesService.getTfsSchedulerConfig).mockResolvedValue(
        {
          tfsAutoSync: true,
          tfsSyncInterval: 'hourly',
        } as any
      );
      vi.mocked(userPreferencesService.getTfsConfig).mockResolvedValue({
        enabled: true,
        organizationUrl: 'https://dev.azure.com/test',
        personalAccessToken: 'token123',
      } as any);
      vi.mocked(prisma.user.findFirst).mockResolvedValue({
        id: 'user1',
      } as any);
      vi.mocked(mockTfsService.testConnection).mockResolvedValue(true);
      vi.mocked(mockTfsService.syncTasks).mockResolvedValue({
        success: true,
        pullRequestsCreated: 5,
        pullRequestsUpdated: 3,
        pullRequestsSkipped: 1,
      } as any);

      await scheduler.start('user1');

      // Avancer le timer pour déclencher la synchronisation
      vi.advanceTimersByTime(60 * 60 * 1000); // 1 heure

      // Attendre que la synchronisation soit exécutée
      await vi.waitFor(() => {
        expect(mockTfsService.syncTasks).toHaveBeenCalled();
      });

      scheduler.stop();
    });

    it('devrait gérer les erreurs de connexion', async () => {
      vi.mocked(userPreferencesService.getTfsSchedulerConfig).mockResolvedValue(
        {
          tfsAutoSync: true,
          tfsSyncInterval: 'hourly',
        } as any
      );
      vi.mocked(userPreferencesService.getTfsConfig).mockResolvedValue({
        enabled: true,
        organizationUrl: 'https://dev.azure.com/test',
        personalAccessToken: 'token123',
      } as any);
      vi.mocked(mockTfsService.testConnection).mockResolvedValue(false);

      await scheduler.start('user1');

      vi.advanceTimersByTime(60 * 60 * 1000);
      await vi.waitFor(() => {
        expect(mockTfsService.testConnection).toHaveBeenCalled();
      });

      scheduler.stop();
    });
  });

  describe('getNextSyncTime', () => {
    it('devrait retourner null si pas démarré', async () => {
      const nextTime = await scheduler.getNextSyncTime();

      expect(nextTime).toBeNull();
    });

    it('devrait calculer le prochain moment de synchronisation', async () => {
      const mockDate = new Date('2024-01-15T12:00:00Z');
      vi.mocked(getToday).mockReturnValue(mockDate);
      vi.mocked(addMinutes).mockReturnValue(new Date('2024-01-15T13:00:00Z'));

      vi.mocked(userPreferencesService.getTfsSchedulerConfig).mockResolvedValue(
        {
          tfsAutoSync: true,
          tfsSyncInterval: 'hourly',
        } as any
      );
      vi.mocked(userPreferencesService.getTfsConfig).mockResolvedValue({
        enabled: true,
        organizationUrl: 'https://dev.azure.com/test',
        personalAccessToken: 'token123',
      } as any);

      await scheduler.start('user1');
      const nextTime = await scheduler.getNextSyncTime();

      expect(nextTime).not.toBeNull();
      expect(addMinutes).toHaveBeenCalled();
    });
  });

  describe('getStatus', () => {
    it('devrait retourner le statut du scheduler', async () => {
      vi.mocked(userPreferencesService.getTfsSchedulerConfig).mockResolvedValue(
        {
          tfsAutoSync: true,
          tfsSyncInterval: 'daily',
        } as any
      );
      vi.mocked(userPreferencesService.getTfsConfig).mockResolvedValue({
        enabled: true,
        organizationUrl: 'https://dev.azure.com/test',
        personalAccessToken: 'token123',
      } as any);

      await scheduler.start('user1');
      const status = await scheduler.getStatus('user1');

      expect(status.isRunning).toBe(true);
      expect(status.isEnabled).toBe(true);
      expect(status.interval).toBe('daily');
      expect(status.tfsConfigured).toBe(true);
    });

    it('devrait retourner le statut si pas démarré', async () => {
      vi.mocked(userPreferencesService.getTfsSchedulerConfig).mockResolvedValue(
        {
          tfsAutoSync: false,
          tfsSyncInterval: 'hourly',
        } as any
      );
      vi.mocked(userPreferencesService.getTfsConfig).mockResolvedValue({
        enabled: false,
      } as any);

      const status = await scheduler.getStatus('user1');

      expect(status.isRunning).toBe(false);
      expect(status.isEnabled).toBe(false);
    });
  });
});
