module JamRuby
  class RecordedTrackObserver < ActiveRecord::Observer

    # if you change the this class, tests really should accompany.  having alot of logic in observers is really tricky, as we do here
    observe JamRuby::RecordedTrack

    def before_validation(recorded_track)


      # if we see that a part was just uploaded entirely, validate that we can find the part that was just uploaded
      if recorded_track.is_part_uploading_was && !recorded_track.is_part_uploading
        begin
          aws_part = recorded_track.s3_manager.multiple_upload_find_part(recorded_track[:url], recorded_track.upload_id, recorded_track.next_part_to_upload - 1)
          # calling size on a part that does not exist will throw an exception... that's what we want
          aws_part.size
        rescue SocketError => e
          raise # this should cause a 500 error, which is what we want.  The client will retry later on 500.
        rescue Exception => e
          recorded_track.errors.add(:next_part_to_upload, ValidationMessages::PART_NOT_FOUND_IN_AWS)
        rescue RuntimeError => e
          recorded_track.errors.add(:next_part_to_upload, ValidationMessages::PART_NOT_FOUND_IN_AWS)
        rescue
          recorded_track.errors.add(:next_part_to_upload, ValidationMessages::PART_NOT_FOUND_IN_AWS)
        end

      end

      # if we detect that this just became fully uploaded -- if so, tell s3 to put the parts together
      if recorded_track.marking_complete && !recorded_track.fully_uploaded_was && recorded_track.fully_uploaded

        multipart_success = false
        begin
          recorded_track.s3_manager.multipart_upload_complete(recorded_track[:url], recorded_track.upload_id)
          multipart_success = true
        rescue SocketError => e
          raise # this should cause a 500 error, which is what we want.  The client will retry later.
        rescue Exception => e
            #recorded_track.reload
            recorded_track.reset_upload
            recorded_track.errors.add(:upload_id, ValidationMessages::BAD_UPLOAD)
        end

        # tell all users that a download is available, except for the user who just uploaded
        recorded_track.recording.users.each do |user|
          Notification.send_download_available(recorded_track.user_id) unless user == recorded_track.user
        end

      end
    end

    def after_commit(recorded_track)

    end

    # here we tick upload failure counts, or revert the state of the model, as needed
    def after_rollback(recorded_track)
      # if fully uploaded, don't increment failures
      if recorded_track.fully_uploaded
        return
      end

      # increment part failures if there is a part currently being uploaded
      if recorded_track.is_part_uploading_was
       #recorded_track.reload # we don't want anything else that the user set to get applied
        recorded_track.increment_part_failures(recorded_track.part_failures_was)
        if recorded_track.part_failures >= APP_CONFIG.max_track_part_upload_failures
          # save upload id before we abort this bad boy
          upload_id = recorded_track.upload_id
          begin
            recorded_track.s3_manager.multipart_upload_abort(recorded_track[:url], upload_id)
          rescue => e
            puts e.inspect
          end
          recorded_track.reset_upload
          if recorded_track.upload_failures >= APP_CONFIG.max_track_upload_failures
            # do anything?
          end
        end
      end

    end

    def before_save(recorded_track)
      # if we are on the 1st part, then we need to make sure we can save the upload_id
      if recorded_track.next_part_to_upload == 1
        recorded_track.upload_id = recorded_track.s3_manager.multipart_upload_start(recorded_track[:url])
      end
    end
  end
end