module RailsPerformance
  module Reports
    class BaseReport
      attr_reader :db, :group, :sort, :title

      def initialize(db, group: nil, sort: nil, title: nil)
        @db = db
        @group = group
        @sort = sort
        @title = title

        set_defaults
      end

      def set_defaults
      end

      def collect
        db.group_by(group).each_with_object([]) do |(k, v), res|
          res << yield(k, v)
        end
      end

      def self.time_in_app_time_zone(time)
        app_time_zone = ::Rails.application.config.time_zone
        if app_time_zone.present?
          time.in_time_zone(app_time_zone)
        else
          time
        end
      end

      # TODO: simplify this method, and combine with nullify_data
      def calculate_data
        now = RailsPerformance::Utils.kind_of_now
        now = now.change(sec: 0, usec: 0)
        stop = now # Time.at(60 * (now.to_i / 60), in:)
        offset = 0 # RailsPerformance::Reports::BaseReport.time_in_app_time_zone(now).utc_offset
        current = stop - RailsPerformance.duration

        @data = []
        all = {}

        db.group_by(group).each do |(k, v)|
          yield(all, k, v)
        end

        # add blank columns
        while current <= stop
          key = current.strftime(RailsPerformance::FORMAT)
          views = all[key].presence || 0
          @data << [(current.to_i + offset) * 1000, views.round(2)]
          current += 1.minute
        end

        # sort by time
        @data.sort!
      end

      # Generate series for our time range -> (now - duration)..now
      # {
      #   1732125540000 => 0,
      #   1732125550000 => 0,
      #   ....
      # }
      def nil_data(duration = RailsPerformance.duration)
        @nil_data ||= begin
          result = {}
          now = RailsPerformance::Utils.kind_of_now
          now = now.change(sec: 0, usec: 0)
          stop = now # Time.at(60 * (now.to_i / 60))
          offset = 0 # RailsPerformance::Reports::BaseReport.time_in_app_time_zone(now).utc_offset
          current = stop - duration

          while current <= stop
            current.strftime(RailsPerformance::FORMAT)
            result[(current.to_i + offset) * 1000] = nil
            current += 1.minute
          end

          result
        end
      end

      # {
      #   1732125540000 => 1,
      #   1732125550000 => 0,
      # }
      def nullify_data(input, duration = RailsPerformance.duration)
        nil_data(duration).merge(input).sort
      end
    end
  end
end
