class MoodCalendarService def self.generate_calendar(user, start_date: nil, end_date: nil) data = user.moods.includes(:mode) .order(:recorded_at) .map { |mood| { mode: mood.mode, recorded_at: mood.recorded_at } } day_logs_by_date = user.day_logs.index_by(&:day) if data.empty? start_date = Date.current else start_date ||= data.first[:recorded_at].to_date end start_date = start_date.to_date end_date = end_date ? end_date.to_date : [ Date.current, start_date + 5.months ].max =begin if end_date.nil? end_date = start_date + 5.months else end_date = end_date.to_date end =end data_by_date = data.group_by { |d| d[:recorded_at].to_date } .transform_values { |entries| entries.max_by { |e| e[:recorded_at] } } last_mode = data.select { |d| d[:recorded_at].to_date < start_date } .max_by { |d| d[:recorded_at] } &.[](:mode) complete_data = (start_date..end_date).map do |date| day_log = day_logs_by_date[date] if data_by_date[date] last_mode = data_by_date[date][:mode] data_by_date[date].merge(day_log: day_log) else { mode: nil, recorded_at: date.to_datetime, guess: last_mode, day_log: day_log } end end complete_data.group_by { |d| d[:recorded_at].to_date.beginning_of_month } .map do |month_start, _| first_monday = month_start first_monday = first_monday.next_occurring(:monday) unless first_monday.monday? 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? month_end = next_first_monday - 1.day data_hash = complete_data.index_by { |d| d[:recorded_at].to_date } all_days = (first_monday..month_end).map do |date| data_hash[date] || { mode: nil, recorded_at: date.to_datetime, guess: nil, day_log: nil } end 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