require 'aws-sdk'

class ApiMusicSessionsController < ApiController

  # have to be signed in currently to see this screen
  before_filter :api_signed_in_user
  before_filter :lookup_session,   only: [:show, :update, :delete]
  skip_before_filter :api_signed_in_user, only: [:perf_upload]

  respond_to :json

  def index
    # params[:participants] is either nil, meaning "everything", or it's an array of musician ids
    # params[:genres] is either nil, meaning "everything", or it's an array of genre ids
    # params[:friends_only] does the obvious.
    # params[:my_bands_only] also does the obvious.
    # Importantly, friends and my_bands are ORed not ANDed. So, if you specify both as true, you'll get more results, not fewer.
    @music_sessions = MusicSession.index(current_user, params[:participants], params[:genres], params[:friends_only], params[:my_bands_only], params[:keyword])
  end

  def create
    client_id = params[:client_id]

    if client_id.nil?
      raise JamArgumentError, "client_id must be specified"
    end

    if !params[:intellectual_property]
      raise JamArgumentError, "You must agree to the intellectual property terms"
    end

    band = Band.find(params[:band]) unless params[:band].nil?

    @music_session = MusicSessionManager.new.create(
      current_user,
      client_id,
      params[:description],
      params[:musician_access],
      params[:approval_required],
      params[:fan_chat],
      params[:fan_access],
      band,
      params[:genres],
      params[:tracks],
      params[:legal_terms])

    if @music_session.errors.any?
      # we have to do this because api_session_detail_url will fail with a bad @music_session
      response.status = :unprocessable_entity
      respond_with @music_session
    else
      respond_with @music_session, responder: ApiResponder, :location => api_session_detail_url(@music_session)
    end
  end

  def show
    unless @music_session.can_see? current_user
      raise ActiveRecord::RecordNotFound
    end
  end

  def update
    @music_session = MusicSessionManager.new.update(
      @music_session, 
      params[:description],
      params[:genres],
      params[:musician_access],
      params[:approval_required],
      params[:fan_chat],
      params[:fan_access])

    if @music_session.errors.any?
      # we have to do this because api_session_detail_url will fail with a bad @music_session
      response.status = :unprocessable_entity
      respond_with @music_session
    else
      respond_with @music_session, responder: ApiResponder, :location => api_session_detail_url(@music_session)
    end
  end

  def participant_show
    @connection = Connection.find_by_client_id(params[:id])
  end

  def participant_create

    @connection = MusicSessionManager.new.participant_create(
      current_user,
      params[:id],
      params[:client_id],
      params[:as_musician],
      params[:tracks])

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

  def participant_delete
    client_id = params[:id]
    @connection = Connection.find_by_client_id!(client_id)
    music_session = MusicSession.find(@connection.music_session_id)

    MusicSessionManager.new.participant_delete(current_user, @connection, music_session)

    respond_with @connection, responder: ApiResponder
  end

  def participant_rating
      @history = MusicSessionUserHistory.find(params[:id])
      @history.rating = params[:rating]
      @history.save

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

  def lookup_session
    @music_session = MusicSession.find(params[:id])
  end
 
  def track_index
    @tracks = Track.index(current_user, params[:id])
  end

  def track_show
    begin
      @track = Track.joins(:connection)
                    .where(:connections => {:user_id => "#{current_user.id}"})
                    .find(params[:track_id])

    rescue ActiveRecord::RecordNotFound
      render :json => { :message => ValidationMessages::TRACK_NOT_FOUND }, :status => 404 
    end
  end

  def track_create
    @track = Track.save(nil,
                        params[:connection_id],
                        params[:instrument_id],
                        params[:sound])

    respond_with @track, responder: ApiResponder, :status => 201, :location => api_session_track_detail_url(@track.connection.music_session, @track)
  end

  def track_update
    begin
      @track = Track.save(params[:track_id],
                          nil,
                          params[:instrument_id],
                          params[:sound])
      
      respond_with @track, responder: ApiResponder, :status => 200

    rescue ActiveRecord::RecordNotFound
      render :json => { :message => ValidationMessages::TRACK_NOT_FOUND }, :status => 404 
    end
  end

  def track_destroy
    begin
      @track = Track.find(params[:track_id])
      unless @track.nil?
        @track.delete
        respond_with responder: ApiResponder, :status => 204
      end
    rescue ActiveRecord::RecordNotFound
      render :json => { :message => ValidationMessages::TRACK_NOT_FOUND }, :status => 404 
    end
  end

  def perf_upload
    # example of using curl to access this API:
    # curl -L -T some_file -X PUT http://localhost:3000/api/sessions/[SESSION_ID]/perf.json?client_id=[CLIENT_ID]

    music_session_history = MusicSessionHistory.find_by_music_session_id(params[:id])
    msuh = MusicSessionUserHistory.find_by_client_id(params[:client_id])

    @perfdata = MusicSessionPerfData.new
    @perfdata.client_id = params[:client_id]
    @perfdata.music_session_history = music_session_history
    unless @perfdata.save
      # we have to do this because api_session_detail_url will fail with a bad @music_session
      response.status = :unprocessable_entity
      respond_with @perfdata
      return
    end

    if SampleApp::Application.config.storage_type == :fog
      uri = @perfdata.uri
      s3 = AWS::S3.new(:access_key_id => SampleApp::Application.config.aws_access_key_id,
                       :secret_access_key => SampleApp::Application.config.aws_secret_access_key)
      bucket = s3.buckets[SampleApp::Application.config.aws_bucket]

      read_url = bucket.objects[uri].url_for(:read, 
                                             # :expires => SampleApp::Application.config.perf_data_signed_url_timeout * 90, 
                                             :'response_content_type' => 'text/csv').to_s
      @perfdata.update_attribute(:uri, read_url)

      write_url = bucket.objects[uri].url_for(:write, 
                                              :expires => SampleApp::Application.config.perf_data_signed_url_timeout, 
                                              :'response_content_type' => 'text/csv').to_s
      logger.debug("*** client can upload to url #{write_url}")
      redirect_to write_url

    else
      if params[:redirected_back].nil? || !params[:redirected_back]
        # first time that a client has asked to do a PUT (not redirected back here)
        redirect_to request.fullpath + '&redirected_back=true'
      else
        # we should store it here to aid in development, but we don't have to until someone wants the feature
        # so... just return 200
        render :json => { :id => @perfdata.id }, :status => 200
      end

    end

  end
end
