import { prisma } from './db/client';
import { z } from 'zod';
import type { SymptomEntry } from '@prisma/client';

// Schéma de validation pour les entrées de symptômes
export const symptomEntrySchema = z.object({
  pain_level: z.number().min(0).max(10),
  fatigue_level: z.number().min(0).max(10),
  other_symptoms: z.string().optional(),
  timestamp: z.date()
});

// Interface pour les résultats des opérations sur les symptômes
export interface SymptomResult {
  success: boolean;
  data?: SymptomEntry | SymptomEntry[];
  message?: string;
}

// Fonction pour créer une nouvelle entrée de symptômes
export async function createSymptomEntry(
  userId: string,
  data: {
    pain_level: number;
    fatigue_level: number;
    other_symptoms?: string;
    timestamp: Date;
  }
): Promise<SymptomResult> {
  try {
    // Validation des données avec Zod
    symptomEntrySchema.parse(data);

    // Création de l'entrée dans la base de données
    const entry = await prisma.symptomEntry.create({
      data: {
        user_id: userId,
        pain_level: data.pain_level,
        fatigue_level: data.fatigue_level,
        other_symptoms: data.other_symptoms || null,
        timestamp: data.timestamp
      }
    });

    return {
      success: true,
      data: entry
    };
  } catch (error) {
    console.error('Erreur lors de la création d\'une entrée de symptômes:', error);
    return {
      success: false,
      message: "Une erreur est survenue lors de l'enregistrement des symptômes"
    };
  }
}

// Fonction pour récupérer les entrées de symptômes d'un utilisateur
export async function getSymptomEntriesByUser(
  userId: string,
  options: {
    startDate?: Date;
    endDate?: Date;
    limit?: number;
  } = {}
): Promise<SymptomResult> {
  try {
    const { startDate, endDate, limit } = options;
    
    // Construction du filtre de date si nécessaire
    const dateFilter = {};
    if (startDate || endDate) {
      dateFilter['AND'] = [];
      
      if (startDate) {
        dateFilter['AND'].push({ timestamp: { gte: startDate } });
      }
      
      if (endDate) {
        dateFilter['AND'].push({ timestamp: { lte: endDate } });
      }
    }
    
    // Requête à la base de données
    const entries = await prisma.symptomEntry.findMany({
      where: {
        user_id: userId,
        ...dateFilter
      },
      orderBy: {
        timestamp: 'desc'
      },
      take: limit || undefined
    });

    return {
      success: true,
      data: entries
    };
  } catch (error) {
    console.error('Erreur lors de la récupération des entrées de symptômes:', error);
    return {
      success: false,
      message: "Une erreur est survenue lors de la récupération des symptômes"
    };
  }
}

// Fonction pour récupérer une entrée de symptômes par son ID
export async function getSymptomEntryById(
  entryId: string,
  userId: string
): Promise<SymptomResult> {
  try {
    const entry = await prisma.symptomEntry.findFirst({
      where: {
        id: entryId,
        user_id: userId
      }
    });

    if (!entry) {
      return {
        success: false,
        message: "Entrée non trouvée"
      };
    }

    return {
      success: true,
      data: entry
    };
  } catch (error) {
    console.error('Erreur lors de la récupération d\'une entrée de symptômes:', error);
    return {
      success: false,
      message: "Une erreur est survenue lors de la récupération du symptôme"
    };
  }
}

// Fonction pour mettre à jour une entrée de symptômes
export async function updateSymptomEntry(
  entryId: string,
  userId: string,
  data: {
    pain_level?: number;
    fatigue_level?: number;
    other_symptoms?: string;
    timestamp?: Date;
  }
): Promise<SymptomResult> {
  try {
    // Vérifier que l'entrée appartient bien à l'utilisateur
    const existingEntry = await prisma.symptomEntry.findFirst({
      where: {
        id: entryId,
        user_id: userId
      }
    });

    if (!existingEntry) {
      return {
        success: false,
        message: "Entrée non trouvée ou non autorisée"
      };
    }

    // Mise à jour de l'entrée
    const updatedEntry = await prisma.symptomEntry.update({
      where: {
        id: entryId
      },
      data
    });

    return {
      success: true,
      data: updatedEntry
    };
  } catch (error) {
    console.error('Erreur lors de la mise à jour d\'une entrée de symptômes:', error);
    return {
      success: false,
      message: "Une erreur est survenue lors de la mise à jour du symptôme"
    };
  }
}

// Fonction pour supprimer une entrée de symptômes
export async function deleteSymptomEntry(
  entryId: string,
  userId: string
): Promise<SymptomResult> {
  try {
    // Vérifier que l'entrée appartient bien à l'utilisateur
    const existingEntry = await prisma.symptomEntry.findFirst({
      where: {
        id: entryId,
        user_id: userId
      }
    });

    if (!existingEntry) {
      return {
        success: false,
        message: "Entrée non trouvée ou non autorisée"
      };
    }

    // Suppression de l'entrée
    await prisma.symptomEntry.delete({
      where: {
        id: entryId
      }
    });

    return {
      success: true
    };
  } catch (error) {
    console.error('Erreur lors de la suppression d\'une entrée de symptômes:', error);
    return {
      success: false,
      message: "Une erreur est survenue lors de la suppression du symptôme"
    };
  }
}

// Fonction pour récupérer les statistiques des symptômes d'un utilisateur
export async function getSymptomStats(
  userId: string,
  options: {
    startDate?: Date;
    endDate?: Date;
  } = {}
): Promise<any> {
  try {
    const { startDate, endDate } = options;
    
    // Récupération des entrées pour la période spécifiée
    const entriesResult = await getSymptomEntriesByUser(userId, { startDate, endDate });
    
    if (!entriesResult.success || !Array.isArray(entriesResult.data)) {
      return {
        success: false,
        message: "Impossible de récupérer les données pour les statistiques"
      };
    }
    
    const entries = entriesResult.data as SymptomEntry[];
    
    if (entries.length === 0) {
      return {
        success: true,
        data: {
          painStats: { avg: 0, min: 0, max: 0 },
          fatigueStats: { avg: 0, min: 0, max: 0 },
          totalEntries: 0,
          dailyAverages: []
        }
      };
    }
    
    // Calcul des statistiques pour la douleur
    const painLevels = entries.map(entry => entry.pain_level);
    const avgPain = painLevels.reduce((sum, value) => sum + value, 0) / painLevels.length;
    const minPain = Math.min(...painLevels);
    const maxPain = Math.max(...painLevels);
    
    // Calcul des statistiques pour la fatigue
    const fatigueLevels = entries.map(entry => entry.fatigue_level);
    const avgFatigue = fatigueLevels.reduce((sum, value) => sum + value, 0) / fatigueLevels.length;
    const minFatigue = Math.min(...fatigueLevels);
    const maxFatigue = Math.max(...fatigueLevels);
    
    // Calcul des moyennes quotidiennes
    const dailyMap = new Map();
    
    entries.forEach(entry => {
      const date = entry.timestamp.toISOString().split('T')[0];
      
      if (!dailyMap.has(date)) {
        dailyMap.set(date, {
          date,
          painValues: [],
          fatigueValues: []
        });
      }
      
      const dayData = dailyMap.get(date);
      dayData.painValues.push(entry.pain_level);
      dayData.fatigueValues.push(entry.fatigue_level);
    });
    
    const dailyAverages = Array.from(dailyMap.values()).map(day => {
      const avgPain = day.painValues.reduce((sum, value) => sum + value, 0) / day.painValues.length;
      const avgFatigue = day.fatigueValues.reduce((sum, value) => sum + value, 0) / day.fatigueValues.length;
      
      return {
        date: day.date,
        avgPain: parseFloat(avgPain.toFixed(1)),
        avgFatigue: parseFloat(avgFatigue.toFixed(1))
      };
    });
    
    // Tri par date
    dailyAverages.sort((a, b) => new Date(a.date).getTime() - new Date(b.date).getTime());
    
    return {
      success: true,
      data: {
        painStats: {
          avg: parseFloat(avgPain.toFixed(1)),
          min: minPain,
          max: maxPain
        },
        fatigueStats: {
          avg: parseFloat(avgFatigue.toFixed(1)),
          min: minFatigue,
          max: maxFatigue
        },
        totalEntries: entries.length,
        dailyAverages
      }
    };
  } catch (error) {
    console.error('Erreur lors du calcul des statistiques:', error);
    return {
      success: false,
      message: "Une erreur est survenue lors du calcul des statistiques"
    };
  }
}