module Stripe
  module APIOperations
    module Update
      # Creates or updates an API resource.
      #
      # If the resource doesn't yet have an assigned ID and the resource is one
      # that can be created, then the method attempts to create the resource.
      # The resource is updated otherwise.
      #
      # ==== Attributes
      #
      # * +params+ - Overrides any parameters in the resource's serialized data
      #   and includes them in the create or update. If +:req_url:+ is included
      #   in the list, it overrides the update URL used for the create or
      #   update.
      def save(params={})
        # Let the caller override the URL but avoid serializing it.
        req_url = params.delete(:req_url) || save_url

        # We started unintentionally (sort of) allowing attributes sent to
        # +save+ to override values used during the update. So as not to break
        # the API, this makes that official here.
        update_attributes(params)

        # Now remove any parameters that look like object attributes.
        params = params.reject { |k, _| respond_to?(k) }

        values = self.class.serialize_params(self).merge(params)

        if values.length > 0
          # note that id gets removed here our call to #url above has already
          # generated a uri for this object with an identifier baked in
          values.delete(:id)

          response, opts = request(:post, req_url, values)
          initialize_from(response, opts)
        end
        self
      end

      private

      def save_url
        # This switch essentially allows us "upsert"-like functionality. If the
        # API resource doesn't have an ID set (suggesting that it's new) and
        # its class responds to .create (which comes from
        # Stripe::APIOperations::Create), then use the URL to create a new
        # resource. Otherwise, generate a URL based on the object's identifier
        # for a normal update.
        if self[:id] == nil && self.class.respond_to?(:create)
          self.class.url
        else
          url
        end
      end
    end
  end
end