# frozen_string_literal: true
module TimeBoss
  class Calendar
    module Waypoints
      %i[month quarter half year].each do |type|
        klass = TimeBoss::Calendar.const_get(type.to_s.classify)
        size = klass.const_get("NUM_MONTHS")

        define_method type do |year_index, index = 1|
          month = (index * size) - size + 1
          months = (month .. month + size - 1).map { |i| basis.new(year_index, i) }
          klass.new(self, year_index, index, months.first.start_date, months.last.end_date)
        end

        define_method "#{type}_for" do |date|
          window = send(type, date.year - 1, 1)
          while true
            break window if window.to_range.include?(date)
            window = window.next
          end
        end
      end

      %i[day week month quarter half year].each do |type|
        define_method("this_#{type}") { send("#{type}_for", Date.today) }
        define_method("last_#{type}") { send("this_#{type}").previous }
        define_method("next_#{type}") { send("this_#{type}").next }

        define_method "#{type.to_s.pluralize}_for" do |entry|
          first = send("#{type}_for", entry.start_date)
          constituents = [first]
          until first.end_date >= entry.end_date
            first = first.next
            constituents << first
          end
          constituents
        end

        define_method "#{type.to_s.pluralize}_back" do |quantity|
          windows = []
          window = send("this_#{type}")
          while quantity > 0
            windows << window.dup
            window = window.previous
            quantity -= 1
          end
          windows.reverse
        end

        define_method "#{type.to_s.pluralize}_ago" do |quantity|
          send("#{type.to_s.pluralize}_back", quantity + 1).first
        end

        define_method type.to_s.pluralize do |quantity|
          windows = []
          window = send("this_#{type}")
          while quantity > 0
            windows << window.dup
            window = window.next
            quantity -= 1
          end
          windows
        end

        define_method "#{type.to_s.pluralize}_hence" do |quantity|
          send(type.to_s.pluralize, quantity + 1).last
        end
      end

      %i[yesterday today tomorrow].each do |period|
        define_method(period) { Day.new(self, Date.send(period)) }
      end

      def day(year_index, index)
        year(year_index).days[index - 1]
      end

      def day_for(date)
        Day.new(self, date)
      end

      def week_for(date)
        year_for(date).weeks.find { |w| w.to_range.include?(date) }
      end
    end
  end
end