# app/services/mood_calendar_service.rb class MoodCalendarService def self.generate_calendar(moods, start_date: nil, end_date: Date.current) # Convertir la relation ActiveRecord en tableau de hash data = moods.order(:recorded_at) .pluck(:mode, :recorded_at) .map { |mode, recorded_at| { mode: mode, recorded_at: recorded_at } } return [] if data.empty? # Définir start_date par défaut comme le recorded_at du premier mood start_date ||= data.first[:recorded_at].to_date # Convertir en Date si ce sont des DateTime ou Time start_date = start_date.to_date end_date = end_date.to_date # Grouper par jour et garder le plus récent pour chaque jour data_by_date = data.group_by { |d| d[:recorded_at].to_date } .transform_values { |entries| entries.max_by { |e| e[:recorded_at] } } # Trouver le dernier mood avant start_date pour initialiser le guess last_mode = data.select { |d| d[:recorded_at].to_date < start_date } .max_by { |d| d[:recorded_at] } &.[](:mode) # Générer le tableau complet avec tous les jours complete_data = (start_date..end_date).map do |date| if data_by_date[date] last_mode = data_by_date[date][:mode] data_by_date[date] else { mode: nil, recorded_at: date.to_datetime, guess: last_mode } end end # Regrouper par mois avec semaines commençant au premier lundi complete_data.group_by { |d| d[:recorded_at].to_date.beginning_of_month } .map do |month_start, month_data| # Trouver le premier lundi du mois (à partir du 1er du mois) first_monday = month_start first_monday = first_monday.next_occurring(:monday) unless first_monday.monday? # Trouver le premier lundi du mois SUIVANT next_month_start = month_start.next_month.beginning_of_month next_first_monday = next_month_start next_first_monday = next_first_monday.next_occurring(:monday) unless next_first_monday.monday? # Le dernier jour du mois est le dimanche précédant le premier lundi du mois suivant month_end = next_first_monday - 1.day # Créer un hash pour accès rapide aux données de complete_data (qui contient déjà les guess) data_hash = complete_data.index_by { |d| d[:recorded_at].to_date } # Générer tous les jours du premier lundi jusqu'au dimanche avant le prochain lundi all_days = (first_monday..month_end).map do |date| # Utiliser directement les données de complete_data qui ont déjà le bon guess data_hash[date] || { mode: nil, recorded_at: date.to_datetime, guess: nil } end # Grouper par semaines weeks = all_days.group_by { |d| d[:recorded_at].to_date.beginning_of_week(:monday) } .sort_by { |week_start, _| week_start } .map { |_, week_moods| week_moods } { month: month_start, weeks: weeks } end end end