/**
 * Tests unitaires pour UserPreferencesService
 */

/* eslint-disable @typescript-eslint/no-explicit-any */
import { describe, it, expect, beforeEach, vi } from 'vitest';
import { userPreferencesService } from '../user-preferences';
import { prisma } from '../database';
import { getConfig } from '@/lib/config';
import {
  KanbanFilters,
  ViewPreferences,
  ColumnVisibility,
  JiraConfig,
} from '@/lib/types';
import { TfsConfig } from '@/services/integrations/tfs/tfs';

// Mock de prisma
vi.mock('../database', () => ({
  prisma: {
    user: {
      upsert: vi.fn(),
    },
    userPreferences: {
      upsert: vi.fn(),
      update: vi.fn(),
      findUnique: vi.fn(),
    },
    $executeRaw: vi.fn(),
    $queryRaw: vi.fn(),
  },
}));

// Mock de getConfig
vi.mock('@/lib/config', () => ({
  getConfig: vi.fn(),
}));

describe('UserPreferencesService', () => {
  const userId = 'test-user-id';

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

  describe('Kanban Filters', () => {
    it('devrait sauvegarder les filtres Kanban', async () => {
      const filters: KanbanFilters = {
        search: 'test',
        tags: ['important'],
        priorities: ['high'],
        showCompleted: false,
        sortBy: 'priority',
        showWithDueDate: true,
      };

      vi.mocked(prisma.user.upsert).mockResolvedValue({
        id: userId,
        email: `${userId}@towercontrol.local`,
        name: 'Default User',
        role: 'user',
        password: 'default',
        createdAt: new Date(),
        updatedAt: new Date(),
      } as any);

      vi.mocked(prisma.userPreferences.upsert).mockResolvedValue({
        userId,
        kanbanFilters: filters,
        viewPreferences: {},
        columnVisibility: {},
        jiraConfig: {},
      } as any);

      vi.mocked(prisma.userPreferences.update).mockResolvedValue({
        userId,
        kanbanFilters: filters,
      } as any);

      vi.mocked(prisma.$executeRaw).mockResolvedValue(0);

      await userPreferencesService.saveKanbanFilters(userId, filters);

      expect(prisma.userPreferences.update).toHaveBeenCalledWith({
        where: { userId },
        data: { kanbanFilters: filters },
      });
    });

    it('devrait récupérer les filtres Kanban avec valeurs par défaut', async () => {
      const filters: KanbanFilters = {
        search: 'test',
        tags: ['important'],
        priorities: [],
        showCompleted: true,
        sortBy: '',
        showWithDueDate: false,
      };

      vi.mocked(prisma.user.upsert).mockResolvedValue({
        id: userId,
        email: `${userId}@towercontrol.local`,
        name: 'Default User',
        role: 'user',
        password: 'default',
        createdAt: new Date(),
        updatedAt: new Date(),
      } as any);

      vi.mocked(prisma.userPreferences.upsert).mockResolvedValue({
        userId,
        kanbanFilters: filters,
        viewPreferences: {},
        columnVisibility: {},
        jiraConfig: {},
      } as any);

      vi.mocked(prisma.$executeRaw).mockResolvedValue(0);

      const result = await userPreferencesService.getKanbanFilters(userId);

      expect(result).toHaveProperty('search');
      expect(result).toHaveProperty('tags');
      expect(result).toHaveProperty('priorities');
      expect(result).toHaveProperty('showCompleted');
    });

    it("devrait retourner les valeurs par défaut en cas d'erreur", async () => {
      vi.mocked(prisma.user.upsert).mockRejectedValue(
        new Error('Database error')
      );

      const result = await userPreferencesService.getKanbanFilters(userId);

      expect(result).toHaveProperty('search');
      expect(result.search).toBe('');
    });
  });

  describe('View Preferences', () => {
    it('devrait sauvegarder les préférences de vue', async () => {
      const preferences: ViewPreferences = {
        compactView: true,
        swimlanesByTags: true,
        swimlanesMode: 'tags',
        showObjectives: false,
        showFilters: true,
        objectivesCollapsed: false,
        theme: 'light',
        fontSize: 'large',
        backgroundImage: undefined,
        backgroundBlur: 0,
        backgroundOpacity: 100,
      };

      vi.mocked(prisma.user.upsert).mockResolvedValue({
        id: userId,
        email: `${userId}@towercontrol.local`,
        name: 'Default User',
        role: 'user',
        password: 'default',
        createdAt: new Date(),
        updatedAt: new Date(),
      } as any);

      vi.mocked(prisma.userPreferences.upsert).mockResolvedValue({
        userId,
        kanbanFilters: {},
        viewPreferences: preferences,
        columnVisibility: {},
        jiraConfig: {},
      } as any);

      vi.mocked(prisma.userPreferences.update).mockResolvedValue({
        userId,
        viewPreferences: preferences,
      } as any);

      vi.mocked(prisma.$executeRaw).mockResolvedValue(0);

      await userPreferencesService.saveViewPreferences(userId, preferences);

      expect(prisma.userPreferences.update).toHaveBeenCalledWith({
        where: { userId },
        data: { viewPreferences: preferences },
      });
    });

    it('devrait récupérer le thème', async () => {
      vi.mocked(prisma.user.upsert).mockResolvedValue({
        id: userId,
        email: `${userId}@towercontrol.local`,
        name: 'Default User',
        role: 'user',
        password: 'default',
        createdAt: new Date(),
        updatedAt: new Date(),
      } as any);

      vi.mocked(prisma.userPreferences.upsert).mockResolvedValue({
        userId,
        kanbanFilters: {},
        viewPreferences: { theme: 'light' },
        columnVisibility: {},
        jiraConfig: {},
      } as any);

      vi.mocked(prisma.$executeRaw).mockResolvedValue(0);

      const theme = await userPreferencesService.getTheme(userId);

      expect(theme).toBe('light');
    });
  });

  describe('Column Visibility', () => {
    it('devrait sauvegarder la visibilité des colonnes', async () => {
      const visibility: ColumnVisibility = {
        hiddenStatuses: ['archived', 'cancelled'],
      };

      vi.mocked(prisma.user.upsert).mockResolvedValue({
        id: userId,
        email: `${userId}@towercontrol.local`,
        name: 'Default User',
        role: 'user',
        password: 'default',
        createdAt: new Date(),
        updatedAt: new Date(),
      } as any);

      vi.mocked(prisma.userPreferences.upsert).mockResolvedValue({
        userId,
        kanbanFilters: {},
        viewPreferences: {},
        columnVisibility: visibility,
        jiraConfig: {},
      } as any);

      vi.mocked(prisma.userPreferences.update).mockResolvedValue({
        userId,
        columnVisibility: visibility,
      } as any);

      vi.mocked(prisma.$executeRaw).mockResolvedValue(0);

      await userPreferencesService.saveColumnVisibility(userId, visibility);

      expect(prisma.userPreferences.update).toHaveBeenCalledWith({
        where: { userId },
        data: { columnVisibility: visibility },
      });
    });

    it("devrait toggle la visibilité d'une colonne", async () => {
      vi.mocked(prisma.user.upsert).mockResolvedValue({
        id: userId,
        email: `${userId}@towercontrol.local`,
        name: 'Default User',
        role: 'user',
        password: 'default',
        createdAt: new Date(),
        updatedAt: new Date(),
      } as any);

      vi.mocked(prisma.userPreferences.upsert).mockResolvedValue({
        userId,
        kanbanFilters: {},
        viewPreferences: {},
        columnVisibility: { hiddenStatuses: [] },
        jiraConfig: {},
      } as any);

      vi.mocked(prisma.userPreferences.update).mockResolvedValue({
        userId,
        columnVisibility: { hiddenStatuses: ['archived'] },
      } as any);

      vi.mocked(prisma.$executeRaw).mockResolvedValue(0);

      await userPreferencesService.toggleColumnVisibility(userId, 'archived');

      expect(prisma.userPreferences.update).toHaveBeenCalled();
    });
  });

  describe('Jira Config', () => {
    it('devrait sauvegarder la configuration Jira', async () => {
      const config: JiraConfig = {
        enabled: true,
        baseUrl: 'https://jira.example.com',
        email: 'user@example.com',
        apiToken: 'token123',
        ignoredProjects: [],
      };

      vi.mocked(prisma.user.upsert).mockResolvedValue({
        id: userId,
        email: `${userId}@towercontrol.local`,
        name: 'Default User',
        role: 'user',
        password: 'default',
        createdAt: new Date(),
        updatedAt: new Date(),
      } as any);

      vi.mocked(prisma.userPreferences.upsert).mockResolvedValue({
        userId,
        kanbanFilters: {},
        viewPreferences: {},
        columnVisibility: {},
        jiraConfig: config,
      } as any);

      vi.mocked(prisma.userPreferences.update).mockResolvedValue({
        userId,
        jiraConfig: config,
      } as any);

      vi.mocked(prisma.$executeRaw).mockResolvedValue(0);

      await userPreferencesService.saveJiraConfig(userId, config);

      expect(prisma.userPreferences.update).toHaveBeenCalledWith({
        where: { userId },
        data: { jiraConfig: config },
      });
    });

    it('devrait récupérer la configuration Jira depuis la DB', async () => {
      const config: JiraConfig = {
        enabled: true,
        baseUrl: 'https://jira.example.com',
        email: 'user@example.com',
        apiToken: 'token123',
        ignoredProjects: [],
      };

      vi.mocked(prisma.user.upsert).mockResolvedValue({
        id: userId,
        email: `${userId}@towercontrol.local`,
        name: 'Default User',
        role: 'user',
        password: 'default',
        createdAt: new Date(),
        updatedAt: new Date(),
      } as any);

      vi.mocked(prisma.userPreferences.upsert).mockResolvedValue({
        userId,
        kanbanFilters: {},
        viewPreferences: {},
        columnVisibility: {},
        jiraConfig: config,
      } as any);

      vi.mocked(prisma.$executeRaw).mockResolvedValue(0);

      const result = await userPreferencesService.getJiraConfig(userId);

      expect(result.baseUrl).toBe('https://jira.example.com');
      expect(result.email).toBe('user@example.com');
    });

    it("devrait utiliser les variables d'environnement si pas de config DB", async () => {
      vi.mocked(prisma.user.upsert).mockResolvedValue({
        id: userId,
        email: `${userId}@towercontrol.local`,
        name: 'Default User',
        role: 'user',
        password: 'default',
        createdAt: new Date(),
        updatedAt: new Date(),
      } as any);

      vi.mocked(prisma.userPreferences.upsert).mockResolvedValue({
        userId,
        kanbanFilters: {},
        viewPreferences: {},
        columnVisibility: {},
        jiraConfig: null,
      } as any);

      vi.mocked(prisma.$executeRaw).mockResolvedValue(0);

      vi.mocked(getConfig).mockReturnValue({
        integrations: {
          jira: {
            baseUrl: 'https://env-jira.example.com',
            email: 'env@example.com',
            enabled: true,
          },
        },
      } as any);

      const result = await userPreferencesService.getJiraConfig(userId);

      expect(result.baseUrl).toBe('https://env-jira.example.com');
      expect(result.email).toBe('env@example.com');
    });
  });

  describe('TFS Config', () => {
    it('devrait sauvegarder la configuration TFS', async () => {
      const config: TfsConfig = {
        enabled: true,
        organizationUrl: 'https://dev.azure.com/org',
        projectName: 'MyProject',
        personalAccessToken: 'token123',
        repositories: ['repo1', 'repo2'],
        ignoredRepositories: [],
        maxSyncPeriod: '90d',
      };

      vi.mocked(prisma.user.upsert).mockResolvedValue({
        id: userId,
        email: `${userId}@towercontrol.local`,
        name: 'Default User',
        role: 'user',
        password: 'default',
        createdAt: new Date(),
        updatedAt: new Date(),
      } as any);

      vi.mocked(prisma.userPreferences.upsert).mockResolvedValue({
        userId,
        kanbanFilters: {},
        viewPreferences: {},
        columnVisibility: {},
        jiraConfig: {},
        tfsConfig: config,
      } as any);

      vi.mocked(prisma.userPreferences.update).mockResolvedValue({
        userId,
        tfsConfig: config,
      } as any);

      vi.mocked(prisma.$executeRaw).mockResolvedValue(0);

      await userPreferencesService.saveTfsConfig(userId, config);

      expect(prisma.userPreferences.update).toHaveBeenCalledWith({
        where: { userId },
        data: { tfsConfig: config },
      });
    });

    it('devrait récupérer la configuration TFS', async () => {
      const config: TfsConfig = {
        enabled: true,
        organizationUrl: 'https://dev.azure.com/org',
        projectName: 'MyProject',
        personalAccessToken: 'token123',
        repositories: [],
        ignoredRepositories: [],
        maxSyncPeriod: '90d',
      };

      vi.mocked(prisma.user.upsert).mockResolvedValue({
        id: userId,
        email: `${userId}@towercontrol.local`,
        name: 'Default User',
        role: 'user',
        password: 'default',
        createdAt: new Date(),
        updatedAt: new Date(),
      } as any);

      vi.mocked(prisma.userPreferences.upsert).mockResolvedValue({
        userId,
        kanbanFilters: {},
        viewPreferences: {},
        columnVisibility: {},
        jiraConfig: {},
        tfsConfig: config,
      } as any);

      vi.mocked(prisma.$executeRaw).mockResolvedValue(0);

      const result = await userPreferencesService.getTfsConfig(userId);

      expect(result.organizationUrl).toBe('https://dev.azure.com/org');
      expect(result.projectName).toBe('MyProject');
    });
  });

  describe('Scheduler Config', () => {
    it('devrait sauvegarder la configuration scheduler Jira', async () => {
      vi.mocked(prisma.user.upsert).mockResolvedValue({
        id: userId,
        email: `${userId}@towercontrol.local`,
        name: 'Default User',
        role: 'user',
        password: 'default',
        createdAt: new Date(),
        updatedAt: new Date(),
      } as any);

      vi.mocked(prisma.userPreferences.upsert).mockResolvedValue({
        userId,
        kanbanFilters: {},
        viewPreferences: {},
        columnVisibility: {},
        jiraConfig: {},
      } as any);

      vi.mocked(prisma.$executeRaw).mockResolvedValue(0);

      await userPreferencesService.saveJiraSchedulerConfig(
        userId,
        true,
        'hourly'
      );

      expect(prisma.$executeRaw).toHaveBeenCalled();
    });

    it('devrait récupérer la configuration scheduler Jira', async () => {
      vi.mocked(prisma.user.upsert).mockResolvedValue({
        id: userId,
        email: `${userId}@towercontrol.local`,
        name: 'Default User',
        role: 'user',
        password: 'default',
        createdAt: new Date(),
        updatedAt: new Date(),
      } as any);

      vi.mocked(prisma.userPreferences.upsert).mockResolvedValue({
        userId,
        kanbanFilters: {},
        viewPreferences: {},
        columnVisibility: {},
        jiraConfig: {},
      } as any);

      vi.mocked(prisma.$executeRaw).mockResolvedValue(0);
      vi.mocked(prisma.$queryRaw).mockResolvedValue([
        { jiraAutoSync: 1, jiraSyncInterval: 'hourly' },
      ] as any);

      const result =
        await userPreferencesService.getJiraSchedulerConfig(userId);

      expect(result.jiraAutoSync).toBe(true);
      expect(result.jiraSyncInterval).toBe('hourly');
    });

    it('devrait sauvegarder la configuration scheduler TFS', async () => {
      vi.mocked(prisma.user.upsert).mockResolvedValue({
        id: userId,
        email: `${userId}@towercontrol.local`,
        name: 'Default User',
        role: 'user',
        password: 'default',
        createdAt: new Date(),
        updatedAt: new Date(),
      } as any);

      vi.mocked(prisma.userPreferences.upsert).mockResolvedValue({
        userId,
        kanbanFilters: {},
        viewPreferences: {},
        columnVisibility: {},
        jiraConfig: {},
      } as any);

      vi.mocked(prisma.$executeRaw).mockResolvedValue(0);

      await userPreferencesService.saveTfsSchedulerConfig(
        userId,
        true,
        'daily'
      );

      expect(prisma.$executeRaw).toHaveBeenCalled();
    });

    it('devrait récupérer la configuration scheduler TFS', async () => {
      vi.mocked(prisma.user.upsert).mockResolvedValue({
        id: userId,
        email: `${userId}@towercontrol.local`,
        name: 'Default User',
        role: 'user',
        password: 'default',
        createdAt: new Date(),
        updatedAt: new Date(),
      } as any);

      vi.mocked(prisma.userPreferences.upsert).mockResolvedValue({
        userId,
        kanbanFilters: {},
        viewPreferences: {},
        columnVisibility: {},
        jiraConfig: {},
      } as any);

      vi.mocked(prisma.$executeRaw).mockResolvedValue(0);
      vi.mocked(prisma.$queryRaw).mockResolvedValue([
        { tfsAutoSync: 1, tfsSyncInterval: 'daily' },
      ] as any);

      const result = await userPreferencesService.getTfsSchedulerConfig(userId);

      expect(result.tfsAutoSync).toBe(true);
      expect(result.tfsSyncInterval).toBe('daily');
    });
  });

  describe('All Preferences', () => {
    it('devrait récupérer toutes les préférences', async () => {
      vi.mocked(prisma.user.upsert).mockResolvedValue({
        id: userId,
        email: `${userId}@towercontrol.local`,
        name: 'Default User',
        role: 'user',
        password: 'default',
        createdAt: new Date(),
        updatedAt: new Date(),
      } as any);

      vi.mocked(prisma.userPreferences.upsert).mockResolvedValue({
        userId,
        kanbanFilters: {},
        viewPreferences: {},
        columnVisibility: {},
        jiraConfig: {},
      } as any);

      vi.mocked(prisma.$executeRaw).mockResolvedValue(0);
      vi.mocked(prisma.$queryRaw).mockResolvedValue([
        { jiraAutoSync: 0, jiraSyncInterval: 'daily' },
        { tfsAutoSync: 0, tfsSyncInterval: 'daily' },
      ] as any);

      vi.mocked(getConfig).mockReturnValue({
        integrations: {
          jira: {
            baseUrl: '',
            email: '',
            enabled: false,
          },
        },
      } as any);

      const result = await userPreferencesService.getAllPreferences(userId);

      expect(result).toHaveProperty('kanbanFilters');
      expect(result).toHaveProperty('viewPreferences');
      expect(result).toHaveProperty('columnVisibility');
      expect(result).toHaveProperty('jiraConfig');
      expect(result).toHaveProperty('jiraAutoSync');
      expect(result).toHaveProperty('jiraSyncInterval');
      expect(result).toHaveProperty('tfsConfig');
      expect(result).toHaveProperty('tfsAutoSync');
      expect(result).toHaveProperty('tfsSyncInterval');
    });

    it('devrait sauvegarder toutes les préférences', async () => {
      const preferences = {
        kanbanFilters: {
          search: '',
          tags: [],
          priorities: [],
          showCompleted: true,
          sortBy: '',
          showWithDueDate: false,
        },
        viewPreferences: {
          compactView: false,
          swimlanesByTags: false,
          swimlanesMode: 'tags' as const,
          showObjectives: true,
          showFilters: true,
          objectivesCollapsed: false,
          theme: 'dark' as const,
          fontSize: 'medium' as const,
          backgroundImage: undefined,
          backgroundBlur: 0,
          backgroundOpacity: 100,
        },
        columnVisibility: {
          hiddenStatuses: [],
        },
        jiraConfig: {
          enabled: false,
          baseUrl: '',
          email: '',
          apiToken: '',
          ignoredProjects: [],
        },
        jiraAutoSync: false,
        jiraSyncInterval: 'daily' as const,
        tfsConfig: {
          enabled: false,
          organizationUrl: '',
          projectName: '',
          personalAccessToken: '',
          repositories: [],
          ignoredRepositories: [],
          maxSyncPeriod: '90d' as const,
        },
        tfsAutoSync: false,
        tfsSyncInterval: 'daily' as const,
      };

      vi.mocked(prisma.user.upsert).mockResolvedValue({
        id: userId,
        email: `${userId}@towercontrol.local`,
        name: 'Default User',
        role: 'user',
        password: 'default',
        createdAt: new Date(),
        updatedAt: new Date(),
      } as any);

      vi.mocked(prisma.userPreferences.upsert).mockResolvedValue({
        userId,
        kanbanFilters: {},
        viewPreferences: {},
        columnVisibility: {},
        jiraConfig: {},
      } as any);

      vi.mocked(prisma.userPreferences.update).mockResolvedValue({
        userId,
      } as any);

      vi.mocked(prisma.$executeRaw).mockResolvedValue(0);

      await userPreferencesService.saveAllPreferences(userId, preferences);

      expect(prisma.userPreferences.update).toHaveBeenCalled();
      expect(prisma.$executeRaw).toHaveBeenCalled();
    });

    it('devrait remettre à zéro toutes les préférences', async () => {
      vi.mocked(prisma.user.upsert).mockResolvedValue({
        id: userId,
        email: `${userId}@towercontrol.local`,
        name: 'Default User',
        role: 'user',
        password: 'default',
        createdAt: new Date(),
        updatedAt: new Date(),
      } as any);

      vi.mocked(prisma.userPreferences.upsert).mockResolvedValue({
        userId,
        kanbanFilters: {},
        viewPreferences: {},
        columnVisibility: {},
        jiraConfig: {},
      } as any);

      vi.mocked(prisma.userPreferences.update).mockResolvedValue({
        userId,
      } as any);

      vi.mocked(prisma.$executeRaw).mockResolvedValue(0);

      await userPreferencesService.resetAllPreferences(userId);

      expect(prisma.userPreferences.update).toHaveBeenCalled();
    });
  });

  describe('Update methods', () => {
    it('devrait mettre à jour partiellement les filtres Kanban', async () => {
      vi.mocked(prisma.user.upsert).mockResolvedValue({
        id: userId,
        email: `${userId}@towercontrol.local`,
        name: 'Default User',
        role: 'user',
        password: 'default',
        createdAt: new Date(),
        updatedAt: new Date(),
      } as any);

      vi.mocked(prisma.userPreferences.upsert).mockResolvedValue({
        userId,
        kanbanFilters: { search: '', tags: [] },
        viewPreferences: {},
        columnVisibility: {},
        jiraConfig: {},
      } as any);

      vi.mocked(prisma.userPreferences.update).mockResolvedValue({
        userId,
        kanbanFilters: { search: 'new', tags: [] },
      } as any);

      vi.mocked(prisma.$executeRaw).mockResolvedValue(0);

      await userPreferencesService.updateKanbanFilters(userId, {
        search: 'new',
      });

      expect(prisma.userPreferences.update).toHaveBeenCalled();
    });

    it('devrait mettre à jour partiellement les préférences de vue', async () => {
      vi.mocked(prisma.user.upsert).mockResolvedValue({
        id: userId,
        email: `${userId}@towercontrol.local`,
        name: 'Default User',
        role: 'user',
        password: 'default',
        createdAt: new Date(),
        updatedAt: new Date(),
      } as any);

      vi.mocked(prisma.userPreferences.upsert).mockResolvedValue({
        userId,
        kanbanFilters: {},
        viewPreferences: { theme: 'dark' },
        columnVisibility: {},
        jiraConfig: {},
      } as any);

      vi.mocked(prisma.userPreferences.update).mockResolvedValue({
        userId,
        viewPreferences: { theme: 'light' },
      } as any);

      vi.mocked(prisma.$executeRaw).mockResolvedValue(0);

      await userPreferencesService.updateViewPreferences(userId, {
        theme: 'light',
      });

      expect(prisma.userPreferences.update).toHaveBeenCalled();
    });
  });
});
