/**
 * Tests unitaires pour BackupScheduler
 */

/* eslint-disable @typescript-eslint/no-explicit-any */
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
import { BackupScheduler } from '../backup-scheduler';
import { backupService } from '../backup';
import { getToday, addMinutes } from '@/lib/date-utils';

// Mock de backupService
vi.mock('../backup', () => ({
  backupService: {
    getConfigSync: vi.fn(),
    createBackup: vi.fn(),
  },
}));

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

describe('BackupScheduler', () => {
  let scheduler: BackupScheduler;

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

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

  describe('start', () => {
    it('devrait démarrer le scheduler si activé', () => {
      vi.mocked(backupService.getConfigSync).mockReturnValue({
        enabled: true,
        interval: 'hourly',
        maxBackups: 5,
        backupPath: '/backups',
      } as any);

      scheduler.start();

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

    it('ne devrait pas démarrer si désactivé', () => {
      vi.mocked(backupService.getConfigSync).mockReturnValue({
        enabled: false,
        interval: 'hourly',
        maxBackups: 5,
        backupPath: '/backups',
      } as any);

      scheduler.start();

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

    it('ne devrait pas démarrer deux fois', () => {
      vi.mocked(backupService.getConfigSync).mockReturnValue({
        enabled: true,
        interval: 'hourly',
        maxBackups: 5,
        backupPath: '/backups',
      } as any);

      scheduler.start();
      const firstCall = scheduler.isActive();
      scheduler.start();
      const secondCall = scheduler.isActive();

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

  describe('stop', () => {
    it('devrait arrêter le scheduler', () => {
      vi.mocked(backupService.getConfigSync).mockReturnValue({
        enabled: true,
        interval: 'hourly',
        maxBackups: 5,
        backupPath: '/backups',
      } as any);

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

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

    it("devrait gérer l'arrêt si pas démarré", () => {
      scheduler.stop();
      expect(scheduler.isActive()).toBe(false);
    });
  });

  describe('restart', () => {
    it('devrait redémarrer le scheduler', () => {
      vi.mocked(backupService.getConfigSync).mockReturnValue({
        enabled: true,
        interval: 'hourly',
        maxBackups: 5,
        backupPath: '/backups',
      } as any);

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

      scheduler.restart();
      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é', () => {
      vi.mocked(backupService.getConfigSync).mockReturnValue({
        enabled: true,
        interval: 'hourly',
        maxBackups: 5,
        backupPath: '/backups',
      } as any);

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

  describe('performScheduledBackup', () => {
    it('devrait exécuter une sauvegarde automatique', async () => {
      vi.mocked(backupService.getConfigSync).mockReturnValue({
        enabled: true,
        interval: 'hourly',
        maxBackups: 5,
        backupPath: '/backups',
      } as any);

      vi.mocked(backupService.createBackup).mockResolvedValue({
        id: '1',
        filename: 'backup.db.gz',
        size: 1024,
        createdAt: new Date(),
        type: 'automatic',
        status: 'success',
      } as any);

      scheduler.start();

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

      // Attendre que la sauvegarde soit exécutée
      await vi.waitFor(() => {
        expect(backupService.createBackup).toHaveBeenCalledWith('automatic');
      });

      scheduler.stop();
    });

    it('devrait gérer les sauvegardes ignorées', async () => {
      vi.mocked(backupService.getConfigSync).mockReturnValue({
        enabled: true,
        interval: 'hourly',
        maxBackups: 5,
        backupPath: '/backups',
      } as any);

      vi.mocked(backupService.createBackup).mockResolvedValue(null);

      scheduler.start();

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

      scheduler.stop();
    });

    it('devrait gérer les erreurs de sauvegarde', async () => {
      vi.mocked(backupService.getConfigSync).mockReturnValue({
        enabled: true,
        interval: 'hourly',
        maxBackups: 5,
        backupPath: '/backups',
      } as any);

      vi.mocked(backupService.createBackup).mockRejectedValue(
        new Error('Backup failed')
      );

      scheduler.start();

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

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

  describe('getIntervalMs', () => {
    it('devrait convertir hourly en millisecondes', () => {
      vi.mocked(backupService.getConfigSync).mockReturnValue({
        enabled: true,
        interval: 'hourly',
        maxBackups: 5,
        backupPath: '/backups',
      } as any);

      scheduler.start();
      const status = scheduler.getStatus();

      expect(status.interval).toBe('hourly');
    });

    it('devrait convertir daily en millisecondes', () => {
      vi.mocked(backupService.getConfigSync).mockReturnValue({
        enabled: true,
        interval: 'daily',
        maxBackups: 5,
        backupPath: '/backups',
      } as any);

      scheduler.start();
      const status = scheduler.getStatus();

      expect(status.interval).toBe('daily');
    });

    it('devrait convertir weekly en millisecondes', () => {
      vi.mocked(backupService.getConfigSync).mockReturnValue({
        enabled: true,
        interval: 'weekly',
        maxBackups: 5,
        backupPath: '/backups',
      } as any);

      scheduler.start();
      const status = scheduler.getStatus();

      expect(status.interval).toBe('weekly');
    });
  });

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

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

    it('devrait calculer le prochain moment de sauvegarde', () => {
      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(backupService.getConfigSync).mockReturnValue({
        enabled: true,
        interval: 'hourly',
        maxBackups: 5,
        backupPath: '/backups',
      } as any);

      scheduler.start();
      const nextTime = scheduler.getNextBackupTime();

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

  describe('getStatus', () => {
    it('devrait retourner le statut du scheduler', () => {
      vi.mocked(backupService.getConfigSync).mockReturnValue({
        enabled: true,
        interval: 'daily',
        maxBackups: 10,
        backupPath: '/custom/backups',
      } as any);

      scheduler.start();
      const status = scheduler.getStatus();

      expect(status.isRunning).toBe(true);
      expect(status.isEnabled).toBe(true);
      expect(status.interval).toBe('daily');
      expect(status.maxBackups).toBe(10);
      expect(status.backupPath).toBe('/custom/backups');
    });

    it('devrait retourner le statut si pas démarré', () => {
      vi.mocked(backupService.getConfigSync).mockReturnValue({
        enabled: false,
        interval: 'hourly',
        maxBackups: 5,
        backupPath: '/backups',
      } as any);

      const status = scheduler.getStatus();

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