require 'spec_helper'
describe ApiJamTracksController, type: :controller do
  render_views
  include CarrierWave::Test::Matchers
  
  before(:all) do
    @original_storage = JamTrackTrackUploader.storage = :fog
    @original_storage_right = JamTrackRightUploader.storage = :fog
    @s3 = S3Manager.new(APP_CONFIG.aws_bucket, APP_CONFIG.aws_access_key_id, APP_CONFIG.aws_secret_access_key)
  end

  after(:all) do
    JamTrackTrackUploader.storage = @original_storage
    JamTrackRightUploader.storage = @original_storage_right
  end

  before(:each) do
    FingerprintWhitelist.destroy_all
    FraudAlert.destroy_all
    MachineFingerprint.destroy_all
    JamTrackRight.destroy_all
    JamTrack.destroy_all
    @user = FactoryGirl.create(:user)
    @jam_track = FactoryGirl.create(:jam_track)
    @jam_track_unavailable = FactoryGirl.create(:jam_track, :status=>'Staging')
    controller.current_user = @user
  end

  describe "ios_order_placed" do
    it "succeeds" do
      post :ios_order_placed, { jam_track_id: @jam_track.id }

      response.status.should == 200
      right = @jam_track.right_for_user(@user)
      right.id.should eq(JSON.parse(response.body)["jam_track_right_id"])
    end
  end

  describe "admin" do
    before(:each) do
      @admin = FactoryGirl.create(:admin)    
      controller.current_user = @admin
    end

    it "can see unavailable" do
      get :index
      response.should be_success
      json = JSON.parse(response.body)
      json["next"].should be_nil
      json["jamtracks"].length.should == 2

      # Create another unavailable track and see:
      jam_track2 = FactoryGirl.create(:jam_track, :status => 'Staging')
      get :index
      response.should be_success
      json = JSON.parse(response.body)
      json["next"].should be_nil
      json["jamtracks"].length.should == 3
    end
  end # describe "admin"

  describe "download functionality" do
    it "lists available tracks" do
      get :index
      response.should be_success
      json = JSON.parse(response.body)
      json["next"].should be_nil
      json["jamtracks"].length.should == 1

      jam_track2 = FactoryGirl.create(:jam_track)
      get :index
      response.should be_success
      json = JSON.parse(response.body)
      json["next"].should be_nil
      json["jamtracks"].length.should == 2
    end

    it "finds a download" do
      #get "/download/#{right.id}/"
      right = JamTrackRight.create(:user=>@user, :jam_track=>@jam_track)
      get :download, { :format=>'json', :id=>@jam_track.id, all_fp: 'all', running_fp: 'running' }

      response.should be_success
      response.status.should == 202
      response.body.should =~ /not available.*/
    end
  end

  describe "purchased" do
    it "can return empty" do
      get :purchased
      response.should be_success
      json = JSON.parse(response.body)
      json['jamtracks'].length.should eq(0)
      json['next'].should eq(nil)
    end

    it "can return single item" do
      # purchase the item for the user
      right = FactoryGirl.create(:jam_track_right, jam_track: @jam_track, user: @user)

      get :purchased
      response.should be_success
      json = JSON.parse(response.body)
      json['jamtracks'].length.should eq(1)
      json['jamtracks'][0]['jam_track_right_id'].should eq(right.id)
      json['next'].should be_nil
    end
  end

  describe "jamtrack plays" do 
    it "handle api call success" do 
      post :played, { id: @jam_track.id, user: @user }
      expect(response.status).to eq(201)
      json = JSON.parse(response.body)
      expect(json.length).to eq(0)
    end
    
    it "handle api call 400" do 
      post :played, { id: '', user: @user }
      expect(response.status).to eq(400)
      json = JSON.parse(response.body)
      expect(/JamTrack ID required/).to match(json['message'])
    end
    
    it "handle api call 500" do 
      post :played, { id: 999, user: @user }
      expect(response.status).to eq(422)
      json = JSON.parse(response.body)
      expect(/Unexpected error occurred/).to match(json['message'])
    end
    
  end

  describe "with a JamTrack" do
    before(:each) do
      # Create a working JamTrack for these tests.  The integrity
      # of this process is checked in other tests:
      @ogg_path = File.join('spec', 'files', 'on.ogg')
      @jam_track = FactoryGirl.create(:jam_track) #jam_track_track.jam_track
      @jam_track.reload
      jam_track_track = @jam_track.jam_track_tracks.first
      
      # 48 kHz:

      @s3.upload(jam_track_track.manually_uploaded_filename(:url_48), @ogg_path)
      jam_track_track[:url_48] = jam_track_track.manually_uploaded_filename(:url_48)

      # 44 kHz:
      @s3.upload(jam_track_track.manually_uploaded_filename(:url_44), File.join('spec', 'files', 'off.ogg'))
      jam_track_track[:url_44] = jam_track_track.manually_uploaded_filename(:url_44)

      #jam_track_track.url.store!(File.open(ogg_path, "rb"))
      jam_track_track.save!
      jam_track_track.reload
      ResqueSpec.reset!
    end
    
    it "download depends on rights" do
      fingerprint={all:'all', running:'running'}
      get :download, :id=>@jam_track.id, sample_rate: 48, all_fp: 'all', running_fp: 'running'
      response.status.should == 403

      right = JamTrackRight.create(:user=>@user, :jam_track=>@jam_track)
      get :download, :id=>@jam_track.id, sample_rate: 48, all_fp: 'all', running_fp: 'running'
      response.status.should == 202
      right.download_count.should eq(0)
      right.private_key_44.should_not be_nil
      right.private_key_48.should_not be_nil

      qname = "#{ResqueSpec.queue_name(JamRuby::JamTracksBuilder)}"
      #puts "ResqueSpec.peek(qname)#{ResqueSpec.peek(qname)}"
      JamTracksBuilder.should have_queued(right.id,48).in(:jam_tracks_builder)

      expect(ResqueSpec.peek(qname).present?).to eq(true)
      ResqueSpec.perform_next(qname)

      JamTracksBuilder.should_not have_queued(right.id,nil).in(:jam_tracks_builder)
      right.reload
      right.private_key_44.should_not be_nil
      right.private_key_48.should_not be_nil
      right.download_count.should eq(0)

      get :download, :id=>@jam_track.id, sample_rate: 48, all_fp: 'all', running_fp: 'running'
      response.status.should == 302
      response.location.should =~ /.*#{Regexp.escape(right.filename(:url_48))}.*/
      right.reload
      right.download_count.should eq(1)
    end

    it "supports multiple bitrates" do      
      get :download, :id=>@jam_track.id, :sample_rate=>44, all_fp: 'all', running_fp: 'running'
      response.status.should == 403

      right = JamTrackRight.create(:user=>@user, :jam_track=>@jam_track)
      get :download, :id=>@jam_track.id, :sample_rate=>44, all_fp: 'all', running_fp: 'running'
      response.status.should == 202
      right.download_count.should eq(0)
      right.private_key_44.should_not be_nil
      right.private_key_48.should_not be_nil

      qname = "#{ResqueSpec.queue_name(JamRuby::JamTracksBuilder)}"
      #puts "ResqueSpec.peek(qname)#{ResqueSpec.peek(qname)}"
      JamTracksBuilder.should have_queued(right.id,44).in(:jam_tracks_builder)

      expect(ResqueSpec.peek(qname).present?).to eq(true)
      ResqueSpec.perform_next(qname)

      JamTracksBuilder.should_not have_queued(right.id, 44).in(:jam_tracks_builder)
      right.reload
      right.private_key_44.should_not be_nil
      right.private_key_48.should_not be_nil
      right.download_count.should eq(0)

      get :download, :id=>@jam_track.id, :sample_rate=>44, all_fp: 'all', running_fp: 'running'
      response.status.should == 302
      response.location.should =~ /.*#{Regexp.escape(right.filename(:url_44))}.*/
      right.reload
      right.download_count.should eq(1)
    end
  end

  describe "keys" do
    it "empty" do
      get :keys, jamtracks: {tracks: []}
      response.status.should == 200
      json = JSON.parse(response.body)
      json.length == 0
    end

    it "track with no rights" do
      get :keys, jamtracks: { tracks: ["#{@jam_track.id}-44"] }
      response.status.should == 200
      json = JSON.parse(response.body)
      json.length.should == 1
      json[0]['id'].should == @jam_track.id.to_s
      json[0]['44'].should_not be_nil
      json[0]['44']['private'].should be_nil
      json[0]['44']['error'].should == 'not_purchased'
      json[0]['48'].should be_nil
    end

    it "track with no key" do

      right = FactoryGirl.create(:jam_track_right, user: @user, private_key_44: nil, private_key_48:nil, jam_track: @jam_track)

      get :keys, jamtracks: { tracks: ["#{@jam_track.id}-44", "#{@jam_track.id}-48"] }
      response.status.should == 200
      json = JSON.parse(response.body)
      json.length.should == 1
      json[0]['44'].should_not be_nil
      json[0]['44']['private'].should_not be_nil
      json[0]['44']['error'].should be_nil
      json[0]['48'].should_not be_nil
      json[0]['48']['private'].should_not be_nil
      json[0]['48']['error'].should be_nil
    end

    it "track with key" do
      right = FactoryGirl.create(:jam_track_right, user: @user, private_key_44: 'abc', private_key_48:nil, jam_track: @jam_track)
      get :keys, jamtracks: { tracks: ["#{@jam_track.id}-44", "#{@jam_track.id}-48"] }
      response.status.should == 200
      json = JSON.parse(response.body)
      json.length.should == 1
      json[0]['id'].should == @jam_track.id.to_s
      json[0]['44'].should_not be_nil
      json[0]['44']['private'].should eq(right.private_key_44)
      json[0]['44']['error'].should be_nil
      json[0]['48'].should_not be_nil
      json[0]['48']['private'].should eq(right.private_key_48)
      json[0]['48']['error'].should be_nil
    end

    it "non-owning user asking for a real track" do
      right = FactoryGirl.create(:jam_track_right, user: FactoryGirl.create(:user), private_key_44: 'abc', private_key_48:nil, jam_track: @jam_track)
      get :keys, jamtracks: { tracks: ["#{@jam_track.id}-44", "#{@jam_track.id}-48"] }
      response.status.should == 200
      json = JSON.parse(response.body)
      json[0]['id'].should == @jam_track.id.to_s
      json[0]['44'].should_not be_nil
      json[0]['44']['private'].should be_nil
      json[0]['44']['error'].should eq('not_purchased')
      json[0]['48'].should_not be_nil
      json[0]['48']['private'].should be_nil
      json[0]['48']['error'].should eq('not_purchased')
    end
  end

  describe "enqueue" do
    it "success" do
      right = FactoryGirl.create(:jam_track_right, user: @user, signed_44: false, signed_48:false)
      right.signing_queued_at.should be_nil
      post :enqueue, {:format=>'json', :id=>right.jam_track.id, fingerprint: {all: 'all', running: 'running'} }
      response.should be_success

      right.reload
      right.signing_queued_at.should_not be_nil
    end
  end

  describe "show_jam_track_right" do
    it "success" do
      right = FactoryGirl.create(:jam_track_right, user: @user)

      get :show_jam_track_right, {:id=>right.jam_track.id}
      response.should be_success
      json = JSON.parse(response.body)
      json['signing_state'].should eq('QUIET')
      json['error_count'].should eq(0)
    end
  end


  describe "guard fraud" do
    after(:each) do
      ENV['RAILS_TEST_IP_ADDRESS'] = nil
    end
    it "stops second user from downloading using same machine" do

      right = JamTrackRight.create(:user=>@user, :jam_track=>@jam_track)
      right.redeemed = true
      right.save!
      get :download, :id=>@jam_track.id, sample_rate: 48, all_fp: 'all', running_fp: 'running'
      response.status.should == 202
      MachineFingerprint.count.should eq(2)

      user2 = FactoryGirl.create(:user)

      controller.current_user = user2

      right = JamTrackRight.create(:user=>user2, :jam_track=>@jam_track)
      right.redeemed = true
      right.save!
      get :download, :id=>@jam_track.id, sample_rate: 48, all_fp: 'all', running_fp: 'running'
      response.status.should == 202

      # no error for the user... but we should have a FraudAlert
      FraudAlert.count.should eq(1)
    end

    it "stops second user from enqueuing using same machine" do
      right = JamTrackRight.create(:user=>@user, :jam_track=>@jam_track)
      right.redeemed = true
      right.save!
      right.signing_queued_at.should be_nil
      post :enqueue, {:format=>'json', :id=>right.jam_track.id, fingerprint: {all: 'all', running: 'running'} }
      response.should be_success

      user2 = FactoryGirl.create(:user)

      controller.current_user = user2

      right = JamTrackRight.create(:user=>user2, :jam_track=>@jam_track)
      right.redeemed = true
      right.save!
      right.signing_queued_at.should be_nil
      post :enqueue, {:format=>'json', :id=>right.jam_track.id, fingerprint: {all: 'all', running: 'running'} }
      response.status.should == 200
      get :download, :id=>@jam_track.id, sample_rate: 48, all_fp: 'all', running_fp: 'running'
      response.status.should == 202
      FraudAlert.count.should eq(1)
    end
  end
end
