/**
 * Tests unitaires pour AnalyticsService
 */

/* eslint-disable @typescript-eslint/no-explicit-any */
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
import { AnalyticsService } from '../analytics';
import { TaskStatus, TaskPriority, TaskSource } from '@/lib/types';
import { prisma } from '@/services/core/database';

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

describe('AnalyticsService', () => {
  const userId = 'test-user-id';
  const mockDate = new Date('2024-01-15T12:00:00Z');

  beforeEach(() => {
    vi.clearAllMocks();
    vi.useFakeTimers();
    vi.setSystemTime(mockDate);
  });

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

  describe('getProductivityMetrics', () => {
    it('devrait calculer les métriques de productivité avec des tâches', async () => {
      const mockTasks = [
        {
          id: '1',
          title: 'Tâche 1',
          description: 'Description 1',
          status: 'done' as TaskStatus,
          priority: 'high' as TaskPriority,
          source: 'manual' as TaskSource,
          sourceId: null,
          ownerId: userId,
          createdAt: new Date('2024-01-10'),
          updatedAt: new Date('2024-01-12'),
          completedAt: new Date('2024-01-12'),
          dueDate: null,
          jiraProject: null,
          jiraKey: null,
          jiraType: null,
          assignee: null,
          taskTags: [],
        },
        {
          id: '2',
          title: 'Tâche 2',
          description: 'Description 2',
          status: 'todo' as TaskStatus,
          priority: 'medium' as TaskPriority,
          source: 'jira' as TaskSource,
          sourceId: 'JIRA-123',
          ownerId: userId,
          createdAt: new Date('2024-01-13'),
          updatedAt: new Date('2024-01-13'),
          completedAt: null,
          dueDate: null,
          jiraProject: 'PROJ',
          jiraKey: 'JIRA-123',
          jiraType: 'Task',
          assignee: null,
          taskTags: [],
        },
      ];

      vi.mocked(prisma.task.findMany).mockResolvedValue(mockTasks as any);

      const result = await AnalyticsService.getProductivityMetrics(userId);

      expect(result).toHaveProperty('completionTrend');
      expect(result).toHaveProperty('velocityData');
      expect(result).toHaveProperty('priorityDistribution');
      expect(result).toHaveProperty('statusFlow');
      expect(result).toHaveProperty('weeklyStats');

      expect(result.completionTrend.length).toBeGreaterThan(0);
      expect(result.priorityDistribution.length).toBeGreaterThan(0);
      expect(result.statusFlow.length).toBeGreaterThan(0);
    });

    it('devrait gérer une liste vide de tâches', async () => {
      vi.mocked(prisma.task.findMany).mockResolvedValue([]);

      const result = await AnalyticsService.getProductivityMetrics(userId);

      expect(result.completionTrend.length).toBeGreaterThan(0);
      expect(result.velocityData).toEqual([]);
      expect(result.priorityDistribution).toEqual([]);
      expect(result.statusFlow).toEqual([]);
    });

    it('devrait filtrer par sources si spécifié', async () => {
      const mockTasks = [
        {
          id: '1',
          title: 'Tâche Jira',
          status: 'done' as TaskStatus,
          priority: 'high' as TaskPriority,
          source: 'jira' as TaskSource,
          sourceId: 'JIRA-1',
          ownerId: userId,
          createdAt: new Date('2024-01-10'),
          updatedAt: new Date('2024-01-10'),
          completedAt: new Date('2024-01-10'),
          dueDate: null,
          description: null,
          jiraProject: null,
          jiraKey: null,
          jiraType: null,
          assignee: null,
          taskTags: [],
        },
        {
          id: '2',
          title: 'Tâche Manual',
          status: 'todo' as TaskStatus,
          priority: 'medium' as TaskPriority,
          source: 'manual' as TaskSource,
          sourceId: null,
          ownerId: userId,
          createdAt: new Date('2024-01-10'),
          updatedAt: new Date('2024-01-10'),
          completedAt: null,
          dueDate: null,
          description: null,
          jiraProject: null,
          jiraKey: null,
          jiraType: null,
          assignee: null,
          taskTags: [],
        },
      ];

      vi.mocked(prisma.task.findMany).mockResolvedValue(mockTasks as any);

      const result = await AnalyticsService.getProductivityMetrics(
        userId,
        undefined,
        ['jira']
      );

      // Vérifier que seules les tâches Jira sont incluses dans les calculs
      const allStatuses = result.statusFlow.map((s) => s.status);
      expect(allStatuses).toContain('Terminé'); // Seule la tâche Jira est done
    });

    it('devrait utiliser une période personnalisée si fournie', async () => {
      const startDate = new Date('2024-01-01');
      const endDate = new Date('2024-01-10');

      vi.mocked(prisma.task.findMany).mockResolvedValue([]);

      await AnalyticsService.getProductivityMetrics(userId, {
        start: startDate,
        end: endDate,
      });

      expect(prisma.task.findMany).toHaveBeenCalled();
    });

    it('devrait calculer correctement la tendance de completion', async () => {
      const mockTasks = [
        {
          id: '1',
          title: 'Tâche complétée',
          status: 'done' as TaskStatus,
          priority: 'high' as TaskPriority,
          source: 'manual' as TaskSource,
          sourceId: null,
          ownerId: userId,
          createdAt: new Date('2024-01-10'),
          updatedAt: new Date('2024-01-12'),
          completedAt: new Date('2024-01-12'),
          dueDate: null,
          description: null,
          jiraProject: null,
          jiraKey: null,
          jiraType: null,
          assignee: null,
          taskTags: [],
        },
      ];

      vi.mocked(prisma.task.findMany).mockResolvedValue(mockTasks as any);

      const result = await AnalyticsService.getProductivityMetrics(userId);

      const completionDay = result.completionTrend.find(
        (day) => day.date === '2024-01-12'
      );
      expect(completionDay).toBeDefined();
      expect(completionDay?.completed).toBe(1);
    });

    it('devrait calculer correctement la distribution des priorités', async () => {
      const mockTasks = [
        {
          id: '1',
          title: 'Tâche haute priorité',
          status: 'todo' as TaskStatus,
          priority: 'high' as TaskPriority,
          source: 'manual' as TaskSource,
          sourceId: null,
          ownerId: userId,
          createdAt: new Date('2024-01-10'),
          updatedAt: new Date('2024-01-10'),
          completedAt: null,
          dueDate: null,
          description: null,
          jiraProject: null,
          jiraKey: null,
          jiraType: null,
          assignee: null,
          taskTags: [],
        },
        {
          id: '2',
          title: 'Tâche moyenne priorité',
          status: 'todo' as TaskStatus,
          priority: 'medium' as TaskPriority,
          source: 'manual' as TaskSource,
          sourceId: null,
          ownerId: userId,
          createdAt: new Date('2024-01-10'),
          updatedAt: new Date('2024-01-10'),
          completedAt: null,
          dueDate: null,
          description: null,
          jiraProject: null,
          jiraKey: null,
          jiraType: null,
          assignee: null,
          taskTags: [],
        },
      ];

      vi.mocked(prisma.task.findMany).mockResolvedValue(mockTasks as any);

      const result = await AnalyticsService.getProductivityMetrics(userId);

      const highPriority = result.priorityDistribution.find(
        (p) => p.priority === 'Élevée'
      );
      const mediumPriority = result.priorityDistribution.find(
        (p) => p.priority === 'Moyenne'
      );

      expect(highPriority).toBeDefined();
      expect(highPriority?.count).toBe(1);
      expect(highPriority?.percentage).toBe(50);

      expect(mediumPriority).toBeDefined();
      expect(mediumPriority?.count).toBe(1);
      expect(mediumPriority?.percentage).toBe(50);
    });

    it('devrait gérer les erreurs de base de données', async () => {
      vi.mocked(prisma.task.findMany).mockRejectedValue(
        new Error('Database error')
      );

      await expect(
        AnalyticsService.getProductivityMetrics(userId)
      ).rejects.toThrow('Impossible de calculer les métriques de productivité');
    });
  });
});
