class ApiRecordingsController < ApiController
  before_filter :api_signed_in_user, :except => [ :add_like ]

  before_filter :lookup_recording, :only => [ :show, :stop, :claim, :discard, :keep, :delete_claim, :add_timeline, :add_video_data, :delete_video_data, :mobile_upload, :mobile_update, :mobile_upload_download, :mobile_upload_delete ]
  before_filter :lookup_recorded_track, :only => [ :download, :upload_next_part, :upload_sign, :upload_part_complete, :upload_complete ]
  before_filter :lookup_recorded_backing_track, :only => [ :backing_track_download, :backing_track_upload_next_part, :backing_track_upload_sign, :backing_track_upload_part_complete, :backing_track_upload_complete ]
  before_filter :lookup_recorded_video, :only => [ :video_upload_sign, :video_upload_start, :video_upload_complete ]
  before_filter :lookup_stream_mix, :only => [ :upload_next_part_stream_mix, :upload_sign_stream_mix, :upload_part_complete_stream_mix, :upload_complete_stream_mix ]

  respond_to :json

  def log
    @log || Logging.logger[ApiRecordingsController]
  end

  def mobile_upload
    mobile_rec = @recording.mobile_recording
    
    if mobile_rec
      mru = MobileRecordingUpload.create(mobile_rec, request.body, params[:file_name])
      
      unless mobile_rec.errors.any?
        render :json => @recording, :status => 200
        return
      end
    end
    response.status = :unprocessable_entity
    render nothing: true 
  end

  def mobile_upload_download
    mobile_rec = @recording.mobile_recording
    if mobile_rec && mobile_rec.mobile_recording_upload
      redirect_to mobile_rec.mobile_recording_upload.sign_url
      return
    end
    response.status = :unprocessable_entity
    render nothing: true 
  end

  def mobile_upload_delete
    mobile_rec = @recording.mobile_recording
    if mobile_rec
      mobile_rec.mobile_recording_upload.try(:destroy)
      render :json => {}, status: 204
      return
    end
    response.status = :unprocessable_entity
    render nothing: true 
  end
  
  def mobile_update
    mobile_rec = @recording.mobile_recording
    
    if mobile_rec
      mobile_rec.data_blob = JSON.parse(request.body.read)
      mobile_rec.save
      
      unless mobile_rec.errors.any?
        render :json => @recording, :status => 200
        return
      end
    end
    response.status = :unprocessable_entity
    render nothing: true 
  end

  def create
    if request.headers['Jamk-Mobile-Env']
      json = JSON.parse(request.body.read)

      record_params = {
        name: json['title'],
        description: json['description'],
        genre: json['genre']['id'],
        record_video: json['isVideo'],
        is_public: false,                       # NOTE:  figure out why we need this one and the yt one
        upload_to_youtube: false,
      }
      result = Recording.create_immediately(current_user, record_params)
      unless result.errors.any?
        
        mr = MobileRecording.new
        mr.data_blob = json
        mr.recording = result
        mr.save!
        
        render :json => result, :status => 200
        return
      end
    end
    response.status = :unprocessable_entity
    render nothing: true 
  end

  def index
    # lists recordings created by for the current user
    @recordings = Recording.list_recordings(current_user, params[:created_by])
  end

  # Returns all files this user should be uploading from his client
  def list_uploads
    begin
      result = Recording.list_uploads(current_user, params[:limit], params[:since])
      render :json => result, :status => 200
    rescue
      render :json => { :message => "could not produce list of files" }, :status => 403
    end
  end

  # Returns all files that the user can download
  def list_downloads
    begin
      render :json => Recording.list_downloads(current_user, params[:limit], params[:since]), :status => 200
    rescue
      render :json => { :message => "could not produce list of files" }, :status => 403
    end
  end

  def show
  end

  def show_recorded_track
    @recorded_track = RecordedTrack.find_by_recording_id_and_client_track_id(params[:id], params[:track_id])
  end

  def show_recorded_backing_track
    @recorded_backing_track = RecordedBackingTrack.find_by_recording_id_and_client_track_id(params[:id], params[:track_id])
  end

  def download # track
    raise JamPermissionError, ValidationMessages::PERMISSION_VALIDATION_ERROR unless @recorded_track.can_download?(current_user)

    @recorded_track.current_user = current_user
    @recorded_track.update_download_count

    @recorded_track.valid?
    if !@recorded_track.errors.any?
      @recorded_track.save!
      redirect_to @recorded_track.sign_url(120, false)  # !is_native_client? - no indicator to indicate this
    else
      render :json => { :message => "download limit surpassed" }, :status => 404
    end
  end

  def backing_track_download
    raise JamPermissionError, ValidationMessages::PERMISSION_VALIDATION_ERROR unless @recorded_backing_track.can_download?(current_user)

    @recorded_backing_track.current_user = current_user
    @recorded_backing_track.update_download_count

    @recorded_backing_track.valid?
    if !@recorded_backing_track.errors.any?
      @recorded_backing_track.save!
      redirect_to @recorded_backing_track.sign_url(120, false) # !is_native_client? - no indicator to indicate this
    else
      render :json => { :message => "download limit surpassed" }, :status => 404
    end
  end

  def create_immediately

    @recording = Recording.create_immediately(current_user, params)

    if @recording.errors.any?
      response.status = :unprocessable_entity
      respond_with @recording
    else
      respond_with @recording, responder: ApiResponder, :location => api_recordings_detail_url(@recording)
    end
  end
  
  def start
    music_session = ActiveMusicSession.find(params[:music_session_id])

    raise JamPermissionError, ValidationMessages::PERMISSION_VALIDATION_ERROR unless music_session.users.exists?(current_user.id)

    @recording = Recording.start(music_session, current_user, record_video: params[:record_video])

    if @recording.errors.any?
      response.status = :unprocessable_entity
      respond_with @recording
    else
      respond_with @recording, responder: ApiResponder, :location => api_recordings_detail_url(@recording)
    end
  end
  
  def stop

    @recording.stop

    if @recording.errors.any?
      response.status = :unprocessable_entity
      respond_with @recording
    else
      respond_with @recording, responder: ApiResponder, :location => api_recordings_detail_url(@recording)
    end
  end

  # claim will create a claimed recording for the creator
  def claim
    claim = @recording.claim(current_user, params[:name], params[:description], Genre.find_by_id(params[:genre]), params[:is_public], params[:upload_to_youtube])

    if claim.errors.any?
      response.status = :unprocessable_entity
      respond_with claim
    else
      respond_with claim, responder: ApiResponder, :location => api_session_detail_url(claim)
    end
  end

  def delete_claim
    claim = @recording.claim_for_user(current_user)

    if claim
      claim.discard(current_user)
      if claim.errors.any?
        response.status = :unprocessable_entity
        respond_with claim
      end
    end

    respond_with @recording
  end

  def add_comment
    if params[:id].blank?
      render :json => { :message => "Recording ID is required" }, :status => 400
      return
    end

    if params[:user_id].blank?
      render :json => { :message => "User ID is required" }, :status => 400
      return
    end

    if params[:comment].blank?
      render :json => { :message => "Comment is required" }, :status => 400
      return
    end

    comment = RecordingComment.new
    comment.recording_id = params[:id]
    comment.creator_id = params[:user_id]
    comment.comment = @@html_encoder.encode(params[:comment])
    comment.ip_address = request.remote_ip
    comment.save

    if comment.errors.any?
      render :json => { :errors => comment.errors }, :status => 422
      return
    else
      render :json => {}, :status => 201
      return
    end
  end

  def add_like
    if params[:id].blank?
      render :json => { :message => "Recording ID is required" }, :status => 400
      return
    end

    liker = RecordingLiker.new
    liker.recording_id = params[:id]
    liker.liker_id = params[:user_id]
    liker.claimed_recording_id = params[:claimed_recording_id]
    liker.favorite = true
    liker.ip_address = request.remote_ip
    liker.save

    if liker.errors.any?
      render :json => { :errors => liker.errors }, :status => 422
      return
    else
      render :json => {}, :status => 201
      return
    end
  end

  # discard will tell the server the user has no interest in the recording
  def discard
    @recording.discard(current_user)
    render :json => {}, :status => 200
  end

  def upload_next_part # track
    length = params[:length]
    md5 = params[:md5]

    @recorded_track.upload_next_part(length, md5)

    if @recorded_track.errors.any?

      response.status = :unprocessable_entity
      # this is not typical, but please don't change this line unless you are sure it won't break anything
      # this is needed because after_rollback in the RecordedTrackObserver touches the model and something about it's
      # state doesn't cause errors to shoot out like normal.
      render :json => { :errors => @recorded_track.errors }, :status => 422
    else
      result = {
          :part => @recorded_track.next_part_to_upload,
          :offset => @recorded_track.file_offset.to_s
      }

      render :json => result, :status => 200
    end

  end

  def upload_sign # track
    render :json => @recorded_track.upload_sign(params[:md5]), :status => 200
  end

  def upload_part_complete # track
    part = params[:part]
    offset = params[:offset]

    @recorded_track.upload_part_complete(part, offset)

    if @recorded_track.errors.any?
      response.status = :unprocessable_entity
      respond_with @recorded_track
    else
      render :json => {}, :status => 200
    end
  end
  
  def upload_complete # track
    @recorded_track.upload_complete
    @recorded_track.recording.upload_complete

    if @recorded_track.errors.any?
      response.status = :unprocessable_entity
      respond_with @recorded_track
      return
    else
      render :json => {}, :status => 200
    end
  end

  def backing_track_upload_next_part
    length = params[:length]
    md5 = params[:md5]

    @recorded_backing_track.upload_next_part(length, md5)

    if @recorded_backing_track.errors.any?

      response.status = :unprocessable_entity
      # this is not typical, but please don't change this line unless you are sure it won't break anything
      # this is needed because after_rollback in the RecordedTrackObserver touches the model and something about it's
      # state doesn't cause errors to shoot out like normal.
      render :json => { :errors => @recorded_backing_track.errors }, :status => 422
    else
      result = {
          :part => @recorded_backing_track.next_part_to_upload,
          :offset => @recorded_backing_track.file_offset.to_s
      }

      render :json => result, :status => 200
    end

  end

  def backing_track_upload_sign
    render :json => @recorded_backing_track.upload_sign(params[:md5]), :status => 200
  end

  def backing_track_upload_part_complete
    part = params[:part]
    offset = params[:offset]

    @recorded_backing_track.upload_part_complete(part, offset)

    if @recorded_backing_track.errors.any?
      response.status = :unprocessable_entity
      respond_with @recorded_backing_track
    else
      render :json => {}, :status => 200
    end
  end

  def backing_track_upload_complete
    @recorded_backing_track.upload_complete
    @recorded_backing_track.recording.upload_complete

    if @recorded_backing_track.errors.any?
      response.status = :unprocessable_entity
      respond_with @recorded_backing_track
      return
    else
      render :json => {}, :status => 200
    end
  end

  # POST /api/recordings/:id/videos/:video_id/upload_sign
  def video_upload_sign
    length = params[:length]
    @youtube_client.sign_youtube_upload(current_user, @recorded_video.url, length)
  end

  # POST /api/recordings/:id/videos/:video_id/upload_complete
  def video_upload_start
    length = params[:length]
    @youtube_client.youtube_upload_status(current_user, @recorded_video.url, length)    
  end  
  
  # POST /api/recordings/:id/videos/:video_id/upload_complete
  def video_upload_complete
    if @youtube_client.complete_upload(@recorded_video)    
      render :status => 200
    else
      render :status => 422
    end
  end

  def upload_next_part_stream_mix
    length = params[:length]
    md5 = params[:md5]

    @quick_mix.upload_next_part(length, md5)

    if @quick_mix.errors.any?

      response.status = :unprocessable_entity
      # this is not typical, but please don't change this line unless you are sure it won't break anything
      # this is needed because after_rollback in the RecordedTrackObserver touches the model and something about it's
      # state doesn't cause errors to shoot out like normal.
      render :json => { :errors => @quick_mix.errors }, :status => 422
    else
      result = {
          :part => @quick_mix.next_part_to_upload,
          :offset => @quick_mix.file_offset.to_s
      }

      render :json => result, :status => 200
    end

  end

  def upload_sign_stream_mix
    render :json => @quick_mix.upload_sign(params[:md5]), :status => 200
  end

  def upload_part_complete_stream_mix
    part = params[:part]
    offset = params[:offset]

    @quick_mix.upload_part_complete(part, offset)

    if @quick_mix.errors.any?
      response.status = :unprocessable_entity
      respond_with @quick_mix
    else
      render :json => {}, :status => 200
    end
  end

  def upload_complete_stream_mix
    @quick_mix.upload_complete

    if @quick_mix.errors.any?
      response.status = :unprocessable_entity
      respond_with @quick_mix
      return
    else
      render :json => {}, :status => 200
    end
  end

  # metadata
  def add_timeline
    @recording.add_timeline(params)

    render :json => {}, :status => 200
  end

  def add_video_data
    @recording.add_video_data(current_user, params)

    video_id = params[:video_id]

    video_url = "https://www.youtube.com/watch?v=#{video_id}"

    body = ""
    body << "Youtube URL: #{video_url}\n\n"
    body << "User: " + current_user.admin_url + "\n\n"
    body << "Recording Landing: #{recording_detail_url(@recording.id)}\n"

    private_public = @recording.is_public? ? 'Public' : 'Private'
    AdminMailer.social({
                           subject:"#{private_public } Video Uploaded by #{current_user.name}",
                           body:body
                       }).deliver_now

    render :json => {}, :status => 200
  end

  def delete_video_data
    @recording.add_video_data({:video_id => nil})

    render :json => {}, :status => 200
  end

  private

  def lookup_recording
    @recording = Recording.find(params[:id])
    raise JamPermissionError, ValidationMessages::PERMISSION_VALIDATION_ERROR unless @recording.has_access?(current_user)
  end

  def lookup_recorded_track
    @recorded_track = RecordedTrack.find_by_recording_id_and_client_track_id!(params[:id], params[:track_id])
    raise JamPermissionError, ValidationMessages::PERMISSION_VALIDATION_ERROR unless @recorded_track.recording.has_access?(current_user)
  end

  def lookup_recorded_backing_track
    @recorded_backing_track = RecordedBackingTrack.find_by_recording_id_and_client_track_id!(params[:id], params[:track_id])
    raise JamPermissionError, ValidationMessages::PERMISSION_VALIDATION_ERROR unless @recorded_backing_track.recording.has_access?(current_user)
  end

  def lookup_stream_mix
    @quick_mix = QuickMix.find_by_recording_id_and_user_id!(params[:id], current_user.id)
    raise JamPermissionError, ValidationMessages::PERMISSION_VALIDATION_ERROR unless @quick_mix.recording.has_access?(current_user)
  end

  def lookup_recorded_video
    @recorded_video = RecordedVideo.find_by_recording_id_and_client_video_source_id!(params[:id], params[:video_id])
    raise JamPermissionError, ValidationMessages::PERMISSION_VALIDATION_ERROR unless @recorded_video.recording.has_access?(current_user)
  end

end # class
