# workaround for https://github.com/einzige/date_time_attribute/issues/14
require 'date_time_attribute'

module DateTimeAttributeValidate
  extend ActiveSupport::Concern
  include DateTimeAttribute

  module ClassMethods
    def date_time_attribute(*attributes)
      super

      attributes.each do |attribute|
        validate -> { self.send("#{attribute}_datetime_value_valid") }

        # allow resetting the field to nil
        before_validation do
          if self.instance_variable_get("@#{attribute}_is_set")
            date = self.instance_variable_get("@#{attribute}_date_value")
            time = self.instance_variable_get("@#{attribute}_time_value")
            if date.blank? && time.blank?
              self.send("#{attribute}=", nil)
            end
          end
        end

        # remember old date and time values
        define_method("#{attribute}_date_value=") do |val|
          self.instance_variable_set("@#{attribute}_is_set", true)
          self.instance_variable_set("@#{attribute}_date_value", val)
          begin
            self.send("#{attribute}_date=", val)
          rescue
            nil
          end
        end
        define_method("#{attribute}_time_value=") do |val|
          self.instance_variable_set("@#{attribute}_is_set", true)
          self.instance_variable_set("@#{attribute}_time_value", val)
          begin
            self.send("#{attribute}_time=", val)
          rescue
            nil
          end
        end

        # fallback to field when values are not set
        define_method("#{attribute}_date_value") do
          self.instance_variable_get("@#{attribute}_date_value") || self.send("#{attribute}_date").try { |e| e.strftime('%Y-%m-%d') }
        end
        define_method("#{attribute}_time_value") do
          self.instance_variable_get("@#{attribute}_time_value") || self.send("#{attribute}_time").try { |e| e.strftime('%H:%M') }
        end

        private

        # validate date and time
        define_method("#{attribute}_datetime_value_valid") do
          date = self.instance_variable_get("@#{attribute}_date_value")
          unless date.blank? || begin
            Date.parse(date)
          rescue
            nil
          end
            errors.add(attribute, "is not a valid date") # @todo I18n
          end
          time = self.instance_variable_get("@#{attribute}_time_value")
          unless time.blank? || begin
            Time.parse(time)
          rescue
            nil
          end
            errors.add(attribute, "is not a valid time") # @todo I18n
          end
        end
      end
    end
  end
end