# frozen_string_literal: true

module PredictPlanting
  extend ActiveSupport::Concern

  included do
    ## Triggers
    before_save :calculate_lifespan

    def calculate_lifespan
      self.lifespan = (planted_at.present? && finished_at.present? && !failed? ? finished_at - planted_at : nil)
    end

    # dates
    def finish_predicted_at
      if planted_at.blank? || failed?
        nil
      elsif crop.median_lifespan.present?
        planted_at + crop.median_lifespan.days
      elsif crop.parent.present? && crop.parent.median_lifespan.present?
        planted_at + crop.parent.median_lifespan.days
      end
    end

    # days
    def expected_lifespan
      if actual_lifespan.present?
        actual_lifespan
      elsif crop.median_lifespan.present?
        crop.median_lifespan
      elsif crop.parent.present? && crop.parent.median_lifespan.present?
        crop.parent.median_lifespan
      end
    end

    def actual_lifespan
      return unless planted_at.present? && finished_at.present? && !failed?

      (finished_at - planted_at).to_i
    end

    def age_in_days
      return if planted_at.blank?
      return if failed?

      known_last_day ||= finished_at || Time.zone.today
      known_last_day = Time.zone.today if known_last_day > Time.zone.today

      (known_last_day - planted_at).to_i
    end

    def percentage_grown
      Rails.cache.fetch("#{cache_key_with_version}/percentage_grown", expires_in: 8.hours) do
        if finished?
          100
        elsif !planted? || failed?
          0
        elsif crop.perennial || (finish_predicted_at.nil? && finished_at.nil?) # This covers future dated finished_at that hasn't occurrred yet.
          nil
        else
          calculate_percentage_grown
        end
      end
    end

    # states
    def finish_is_predicatable?
      crop.annual? && planted_at.present? && finish_predicted_at.present?
    end

    # Planting has live more then 90 days past predicted finish
    def super_late?
      late? && (finish_predicted_at + 90.days) < Time.zone.today
    end

    def late?
      crop.annual? && !finished && !failed &&
        planted_at.present? &&
        finish_predicted_at.present? &&
        finish_predicted_at <= Time.zone.today
    end

    # Deactivate any plantings over time_limit that are super late in small batches.
    def self.archive!(time_limit: 3.years.ago, limit: 1000)
      active_plantings = Planting.annual.active.where("planted_at < ?", time_limit).order(planted_at: :asc).limit(limit)
      active_plantings.each do |planting|
        if planting.finish_is_predicatable? && planting.super_late?
          planting.finished = true
          planting.save
        end
      end
    end

    private

    def calculate_percentage_grown
      return 0 if age_in_days.to_i < 0

      percent = (age_in_days.to_f / expected_lifespan.to_f) * 100
      (percent > 100 ? 100 : percent)
    end
  end
end
