import {
  TaskStatus,
  KanbanFilters,
  ViewPreferences,
  ColumnVisibility,
  UserPreferences,
  JiraConfig,
  Theme,
} from '@/lib/types';
import { TfsConfig } from '@/services/integrations/tfs/tfs';
import { prisma } from './database';
import { getConfig } from '@/lib/config';

// Valeurs par défaut
const DEFAULT_PREFERENCES: UserPreferences = {
  kanbanFilters: {
    search: '',
    tags: [],
    priorities: [],
    showCompleted: true,
    sortBy: '',
    showWithDueDate: false,
  },
  viewPreferences: {
    compactView: false,
    swimlanesByTags: false,
    swimlanesMode: 'tags',
    showObjectives: true,
    showFilters: true,
    objectivesCollapsed: false,
    theme: 'dark',
    fontSize: 'medium',
    backgroundImage: undefined,
    backgroundBlur: 0,
    backgroundOpacity: 100,
  },
  columnVisibility: {
    hiddenStatuses: [],
  },
  jiraConfig: {
    enabled: false,
    baseUrl: '',
    email: '',
    apiToken: '',
    ignoredProjects: [],
  },
  jiraAutoSync: false,
  jiraSyncInterval: 'daily',
  tfsConfig: {
    enabled: false,
    organizationUrl: '',
    projectName: '',
    personalAccessToken: '',
    repositories: [],
    ignoredRepositories: [],
    maxSyncPeriod: '90d', // Par défaut 90 jours
  },
  tfsAutoSync: false,
  tfsSyncInterval: 'daily',
};

/**
 * Service pour gérer les préférences utilisateur en base de données
 */
class UserPreferencesService {
  /**
   * Récupère ou crée l'entrée user preferences (avec upsert pour éviter les doublons)
   */
  private async getOrCreateUserPreferences(userId: string) {
    // S'assurer que l'utilisateur existe d'abord (upsert pour éviter les doublons)
    await prisma.user.upsert({
      where: { id: userId },
      update: {}, // Ne rien mettre à jour si existe
      create: {
        id: userId,
        email: `${userId}@towercontrol.local`,
        name: 'Default User',
        role: 'user',
        password: 'default', // Mot de passe temporaire
      },
    });

    // Utiliser upsert pour éviter les conditions de course
    const userPrefs = await prisma.userPreferences.upsert({
      where: { userId }, // Utiliser userId au lieu de id
      update: {}, // Ne rien mettre à jour si existe
      create: {
        userId,
        kanbanFilters: DEFAULT_PREFERENCES.kanbanFilters,
        viewPreferences: DEFAULT_PREFERENCES.viewPreferences,
        columnVisibility: DEFAULT_PREFERENCES.columnVisibility,
        jiraConfig: DEFAULT_PREFERENCES.jiraConfig as any, // eslint-disable-line @typescript-eslint/no-explicit-any
      },
    });

    // S'assurer que les nouveaux champs existent (migration douce)
    await this.ensureJiraSchedulerFields(userId);
    await this.ensureTfsSchedulerFields(userId);

    return userPrefs;
  }

  /**
   * S'assure que les champs jiraAutoSync et jiraSyncInterval existent
   */
  private async ensureJiraSchedulerFields(userId: string): Promise<void> {
    try {
      await prisma.$executeRaw`
        UPDATE user_preferences 
        SET jiraAutoSync = COALESCE(jiraAutoSync, ${DEFAULT_PREFERENCES.jiraAutoSync}),
            jiraSyncInterval = COALESCE(jiraSyncInterval, ${DEFAULT_PREFERENCES.jiraSyncInterval})
        WHERE userId = ${userId}
      `;
    } catch (error) {
      // Ignorer les erreurs si les colonnes n'existent pas encore
      console.debug('Migration douce des champs scheduler Jira:', error);
    }
  }

  /**
   * S'assure que les champs tfsAutoSync et tfsSyncInterval existent
   */
  private async ensureTfsSchedulerFields(userId: string): Promise<void> {
    try {
      await prisma.$executeRaw`
        UPDATE user_preferences 
        SET tfsAutoSync = COALESCE(tfsAutoSync, ${DEFAULT_PREFERENCES.tfsAutoSync}),
            tfsSyncInterval = COALESCE(tfsSyncInterval, ${DEFAULT_PREFERENCES.tfsSyncInterval})
        WHERE userId = ${userId}
      `;
    } catch (error) {
      // Ignorer les erreurs si les colonnes n'existent pas encore
      console.debug('Migration douce des champs scheduler TFS:', error);
    }
  }

  // === FILTRES KANBAN ===

  /**
   * Sauvegarde les filtres Kanban
   */
  async saveKanbanFilters(
    userId: string,
    filters: KanbanFilters
  ): Promise<void> {
    try {
      await this.getOrCreateUserPreferences(userId);
      await prisma.userPreferences.update({
        where: { userId },
        data: { kanbanFilters: filters },
      });
    } catch (error) {
      console.warn('Erreur lors de la sauvegarde des filtres Kanban:', error);
      throw error;
    }
  }

  /**
   * Récupère les filtres Kanban
   */
  async getKanbanFilters(userId: string): Promise<KanbanFilters> {
    try {
      const userPrefs = await this.getOrCreateUserPreferences(userId);
      const filters = userPrefs.kanbanFilters as KanbanFilters | null;
      return { ...DEFAULT_PREFERENCES.kanbanFilters, ...(filters || {}) };
    } catch (error) {
      console.warn('Erreur lors de la récupération des filtres Kanban:', error);
      return DEFAULT_PREFERENCES.kanbanFilters;
    }
  }

  // === PRÉFÉRENCES DE VUE ===

  /**
   * Sauvegarde les préférences de vue
   */
  async saveViewPreferences(
    userId: string,
    preferences: ViewPreferences
  ): Promise<void> {
    try {
      await this.getOrCreateUserPreferences(userId);
      await prisma.userPreferences.update({
        where: { userId },
        data: { viewPreferences: preferences },
      });
    } catch (error) {
      console.warn(
        'Erreur lors de la sauvegarde des préférences de vue:',
        error
      );
      throw error;
    }
  }

  /**
   * Récupère les préférences de vue
   */
  async getViewPreferences(userId: string): Promise<ViewPreferences> {
    try {
      const userPrefs = await this.getOrCreateUserPreferences(userId);
      const preferences = userPrefs.viewPreferences as ViewPreferences | null;
      return { ...DEFAULT_PREFERENCES.viewPreferences, ...(preferences || {}) };
    } catch (error) {
      console.warn(
        'Erreur lors de la récupération des préférences de vue:',
        error
      );
      return DEFAULT_PREFERENCES.viewPreferences;
    }
  }

  // === VISIBILITÉ DES COLONNES ===

  /**
   * Sauvegarde la visibilité des colonnes
   */
  async saveColumnVisibility(
    userId: string,
    visibility: ColumnVisibility
  ): Promise<void> {
    try {
      await this.getOrCreateUserPreferences(userId);
      await prisma.userPreferences.update({
        where: { userId },
        data: { columnVisibility: visibility },
      });
    } catch (error) {
      console.warn(
        'Erreur lors de la sauvegarde de la visibilité des colonnes:',
        error
      );
      throw error;
    }
  }

  /**
   * Récupère la visibilité des colonnes
   */
  async getColumnVisibility(userId: string): Promise<ColumnVisibility> {
    try {
      const userPrefs = await this.getOrCreateUserPreferences(userId);
      const visibility = userPrefs.columnVisibility as ColumnVisibility | null;
      return { ...DEFAULT_PREFERENCES.columnVisibility, ...(visibility || {}) };
    } catch (error) {
      console.warn(
        'Erreur lors de la récupération de la visibilité des colonnes:',
        error
      );
      return DEFAULT_PREFERENCES.columnVisibility;
    }
  }

  // === MÉTHODES GLOBALES ===

  /**
   * Récupère uniquement le thème pour le SSR (optimisé)
   */
  async getTheme(userId: string): Promise<Theme> {
    try {
      const userPrefs = await this.getOrCreateUserPreferences(userId);
      const viewPrefs = userPrefs.viewPreferences as ViewPreferences;
      return viewPrefs.theme;
    } catch (error) {
      console.error('Erreur lors de la récupération du thème:', error);
      return DEFAULT_PREFERENCES.viewPreferences.theme; // Fallback
    }
  }

  // === CONFIGURATION JIRA ===

  /**
   * Sauvegarde la configuration Jira
   */
  async saveJiraConfig(userId: string, config: JiraConfig): Promise<void> {
    try {
      await this.getOrCreateUserPreferences(userId);
      await prisma.userPreferences.update({
        where: { userId },
        data: { jiraConfig: config as any }, // eslint-disable-line @typescript-eslint/no-explicit-any
      });
    } catch (error) {
      console.warn('Erreur lors de la sauvegarde de la config Jira:', error);
      throw error;
    }
  }

  /**
   * Récupère la configuration Jira depuis la base de données avec fallback sur les variables d'environnement
   */
  async getJiraConfig(userId: string): Promise<JiraConfig> {
    try {
      const userPrefs = await this.getOrCreateUserPreferences(userId);
      const dbConfig = userPrefs.jiraConfig as JiraConfig | null;

      // Si config en DB, l'utiliser
      if (
        dbConfig &&
        (dbConfig.baseUrl || dbConfig.email || dbConfig.apiToken)
      ) {
        return { ...DEFAULT_PREFERENCES.jiraConfig, ...dbConfig };
      }

      // Sinon fallback sur les variables d'environnement (existant)
      const config = getConfig();
      return {
        baseUrl: config.integrations.jira.baseUrl,
        email: config.integrations.jira.email,
        apiToken: '', // On ne retourne pas le token des env vars pour la sécurité
        enabled: config.integrations.jira.enabled,
      };
    } catch (error) {
      console.warn('Erreur lors de la récupération de la config Jira:', error);
      return DEFAULT_PREFERENCES.jiraConfig;
    }
  }

  // === CONFIGURATION TFS ===

  /**
   * Sauvegarde la configuration TFS
   */
  async saveTfsConfig(userId: string, config: TfsConfig): Promise<void> {
    try {
      await this.getOrCreateUserPreferences(userId);
      await prisma.userPreferences.update({
        where: { userId },
        data: { tfsConfig: config as any }, // eslint-disable-line @typescript-eslint/no-explicit-any
      });
    } catch (error) {
      console.warn('Erreur lors de la sauvegarde de la config TFS:', error);
      throw error;
    }
  }

  /**
   * Récupère la configuration TFS depuis la base de données
   */
  async getTfsConfig(userId: string): Promise<TfsConfig> {
    try {
      const userPrefs = await this.getOrCreateUserPreferences(userId);
      const dbConfig = userPrefs.tfsConfig as TfsConfig | null;

      if (
        dbConfig &&
        (dbConfig.organizationUrl ||
          dbConfig.projectName ||
          dbConfig.personalAccessToken)
      ) {
        return { ...DEFAULT_PREFERENCES.tfsConfig, ...dbConfig };
      }

      return DEFAULT_PREFERENCES.tfsConfig;
    } catch (error) {
      console.warn('Erreur lors de la récupération de la config TFS:', error);
      return DEFAULT_PREFERENCES.tfsConfig;
    }
  }

  /**
   * Sauvegarde les préférences du scheduler TFS
   */
  async saveTfsSchedulerConfig(
    userId: string,
    tfsAutoSync: boolean,
    tfsSyncInterval: 'hourly' | 'daily' | 'weekly'
  ): Promise<void> {
    try {
      await this.getOrCreateUserPreferences(userId);
      await prisma.$executeRaw`
        UPDATE user_preferences 
        SET tfsAutoSync = ${tfsAutoSync}, tfsSyncInterval = ${tfsSyncInterval}
        WHERE userId = ${userId}
      `;
    } catch (error) {
      console.warn(
        'Erreur lors de la sauvegarde de la config scheduler TFS:',
        error
      );
      throw error;
    }
  }

  /**
   * Récupère les préférences du scheduler TFS
   */
  async getTfsSchedulerConfig(userId: string): Promise<{
    tfsAutoSync: boolean;
    tfsSyncInterval: 'hourly' | 'daily' | 'weekly';
  }> {
    try {
      await this.getOrCreateUserPreferences(userId);
      const result = await prisma.$queryRaw<
        Array<{ tfsAutoSync: number; tfsSyncInterval: string }>
      >`
        SELECT tfsAutoSync, tfsSyncInterval FROM user_preferences WHERE userId = ${userId}
      `;

      if (result.length > 0) {
        return {
          tfsAutoSync: Boolean(result[0].tfsAutoSync),
          tfsSyncInterval:
            (result[0].tfsSyncInterval as 'hourly' | 'daily' | 'weekly') ||
            DEFAULT_PREFERENCES.tfsSyncInterval,
        };
      }

      return {
        tfsAutoSync: DEFAULT_PREFERENCES.tfsAutoSync,
        tfsSyncInterval: DEFAULT_PREFERENCES.tfsSyncInterval,
      };
    } catch (error) {
      console.warn(
        'Erreur lors de la récupération de la config scheduler TFS:',
        error
      );
      return {
        tfsAutoSync: DEFAULT_PREFERENCES.tfsAutoSync,
        tfsSyncInterval: DEFAULT_PREFERENCES.tfsSyncInterval,
      };
    }
  }

  // === CONFIGURATION SCHEDULER JIRA ===

  /**
   * Sauvegarde les préférences du scheduler Jira
   */
  async saveJiraSchedulerConfig(
    userId: string,
    jiraAutoSync: boolean,
    jiraSyncInterval: 'hourly' | 'daily' | 'weekly'
  ): Promise<void> {
    try {
      await this.getOrCreateUserPreferences(userId);
      // Utiliser une requête SQL brute temporairement pour éviter les problèmes de types
      await prisma.$executeRaw`
        UPDATE user_preferences 
        SET jiraAutoSync = ${jiraAutoSync}, jiraSyncInterval = ${jiraSyncInterval}
        WHERE userId = ${userId}
      `;
    } catch (error) {
      console.warn(
        'Erreur lors de la sauvegarde de la config scheduler Jira:',
        error
      );
      throw error;
    }
  }

  /**
   * Récupère les préférences du scheduler Jira
   */
  async getJiraSchedulerConfig(userId: string): Promise<{
    jiraAutoSync: boolean;
    jiraSyncInterval: 'hourly' | 'daily' | 'weekly';
  }> {
    try {
      const userPrefs = await this.getOrCreateUserPreferences(userId);
      // Utiliser une requête SQL brute pour récupérer les nouveaux champs
      const result = await prisma.$queryRaw<
        Array<{ jiraAutoSync: number; jiraSyncInterval: string }>
      >`
        SELECT jiraAutoSync, jiraSyncInterval FROM user_preferences WHERE userId = ${userPrefs.userId}
      `;

      if (result.length > 0) {
        return {
          jiraAutoSync: Boolean(result[0].jiraAutoSync),
          jiraSyncInterval:
            (result[0].jiraSyncInterval as 'hourly' | 'daily' | 'weekly') ||
            DEFAULT_PREFERENCES.jiraSyncInterval,
        };
      }

      return {
        jiraAutoSync: DEFAULT_PREFERENCES.jiraAutoSync,
        jiraSyncInterval: DEFAULT_PREFERENCES.jiraSyncInterval,
      };
    } catch (error) {
      console.warn(
        'Erreur lors de la récupération de la config scheduler Jira:',
        error
      );
      return {
        jiraAutoSync: DEFAULT_PREFERENCES.jiraAutoSync,
        jiraSyncInterval: DEFAULT_PREFERENCES.jiraSyncInterval,
      };
    }
  }

  /**
   * Récupère les préférences utilisateur (alias pour getAllPreferences)
   */
  async getUserPreferences(userId: string): Promise<UserPreferences> {
    return this.getAllPreferences(userId);
  }

  /**
   * Récupère toutes les préférences utilisateur
   */
  async getAllPreferences(userId: string): Promise<UserPreferences> {
    const [
      kanbanFilters,
      viewPreferences,
      columnVisibility,
      jiraConfig,
      jiraSchedulerConfig,
      tfsConfig,
      tfsSchedulerConfig,
    ] = await Promise.all([
      this.getKanbanFilters(userId),
      this.getViewPreferences(userId),
      this.getColumnVisibility(userId),
      this.getJiraConfig(userId),
      this.getJiraSchedulerConfig(userId),
      this.getTfsConfig(userId),
      this.getTfsSchedulerConfig(userId),
    ]);

    return {
      kanbanFilters,
      viewPreferences,
      columnVisibility,
      jiraConfig,
      jiraAutoSync: jiraSchedulerConfig.jiraAutoSync,
      jiraSyncInterval: jiraSchedulerConfig.jiraSyncInterval,
      tfsConfig,
      tfsAutoSync: tfsSchedulerConfig.tfsAutoSync,
      tfsSyncInterval: tfsSchedulerConfig.tfsSyncInterval,
    };
  }

  /**
   * Sauvegarde toutes les préférences utilisateur
   */
  async saveAllPreferences(
    userId: string,
    preferences: UserPreferences
  ): Promise<void> {
    await Promise.all([
      this.saveKanbanFilters(userId, preferences.kanbanFilters),
      this.saveViewPreferences(userId, preferences.viewPreferences),
      this.saveColumnVisibility(userId, preferences.columnVisibility),
      this.saveJiraConfig(userId, preferences.jiraConfig),
      this.saveJiraSchedulerConfig(
        userId,
        preferences.jiraAutoSync,
        preferences.jiraSyncInterval
      ),
      this.saveTfsConfig(userId, preferences.tfsConfig),
      this.saveTfsSchedulerConfig(
        userId,
        preferences.tfsAutoSync,
        preferences.tfsSyncInterval
      ),
    ]);
  }

  /**
   * Remet à zéro toutes les préférences
   */
  async resetAllPreferences(userId: string): Promise<void> {
    try {
      await this.getOrCreateUserPreferences(userId);
      await prisma.userPreferences.update({
        where: { userId },
        data: {
          kanbanFilters: DEFAULT_PREFERENCES.kanbanFilters,
          viewPreferences: DEFAULT_PREFERENCES.viewPreferences,
          columnVisibility: DEFAULT_PREFERENCES.columnVisibility,
          jiraConfig: DEFAULT_PREFERENCES.jiraConfig as any, // eslint-disable-line @typescript-eslint/no-explicit-any
        },
      });
    } catch (error) {
      console.warn('Erreur lors de la remise à zéro des préférences:', error);
      throw error;
    }
  }

  // === MÉTHODES UTILITAIRES ===

  /**
   * Met à jour partiellement les filtres Kanban
   */
  async updateKanbanFilters(
    userId: string,
    updates: Partial<KanbanFilters>
  ): Promise<void> {
    const current = await this.getKanbanFilters(userId);
    await this.saveKanbanFilters(userId, { ...current, ...updates });
  }

  /**
   * Met à jour partiellement les préférences de vue
   */
  async updateViewPreferences(
    userId: string,
    updates: Partial<ViewPreferences>
  ): Promise<void> {
    const current = await this.getViewPreferences(userId);
    await this.saveViewPreferences(userId, { ...current, ...updates });
  }

  /**
   * Met à jour la visibilité d'une colonne spécifique
   */
  async toggleColumnVisibility(
    userId: string,
    status: TaskStatus
  ): Promise<void> {
    const current = await this.getColumnVisibility(userId);
    const hiddenStatuses = new Set(current.hiddenStatuses);

    if (hiddenStatuses.has(status)) {
      hiddenStatuses.delete(status);
    } else {
      hiddenStatuses.add(status);
    }

    await this.saveColumnVisibility(userId, {
      hiddenStatuses: Array.from(hiddenStatuses),
    });
  }
}

// Export de l'instance singleton
export const userPreferencesService = new UserPreferencesService();
