require 'spec_helper'

describe MusicSession do


  let(:creator) {FactoryGirl.create(:user, last_jam_locidispid: 1)}
  let(:some_user) { FactoryGirl.create(:user) }
  let(:music_session1) { FactoryGirl.create(:music_session) }
  let(:music_session2) { FactoryGirl.create(:music_session) }
  let(:music_session3) { FactoryGirl.create(:music_session) }
  let(:music_session4) { FactoryGirl.create(:music_session) }

  describe "validations" do
    it "genre must be set" do
      music_session = FactoryGirl.build(:music_session)
      music_session.genre = nil
      music_session.save.should be_false
      music_session.errors[:genre].should == ["can't be blank"]
    end

    it "updates the fields of a music session properly" do
      genre1 = FactoryGirl.create(:genre)
      genre2 = FactoryGirl.create(:genre)
      genre3 = FactoryGirl.create(:genre)
      genre4 = FactoryGirl.create(:genre)
      creator = FactoryGirl.create(:user)
      session = FactoryGirl.create(:music_session, :creator => creator, :description => "Session", :genre => genre3)
      session.update_attributes({:description => "Session2", :genre => genre1})
      session.reload
      session.description.should == "Session2"
      session.genre.should == genre1
    end

    it "must have legal_terms accepted" do
      user1 = FactoryGirl.create(:user)
      music_session = FactoryGirl.build(:music_session, :creator => user1,  legal_terms: false)
      music_session.save
      music_session.valid?.should be_false
      music_session.errors["legal_terms"].should == ["is not included in the list"]
    end

    it "cannot have profanity in the description" do
      user1 = FactoryGirl.create(:user)
      music_session = FactoryGirl.build(:music_session, :creator => user1, legal_terms: false, :description => "fuck you")
      music_session.save
      music_session.valid?.should be_false
    end
  end

  describe "create" do

    let(:open_params) {
      {
          name: "session 1",
          description: "my session",
          genres: ['ambient'],
          musician_access: true,
          fan_access: true,
          approval_required: true,
          fan_chat: true,
          legal_policy: 'Standard',
          language: 'eng',
          start: "Thu Jul 10 2014 10:00 PM",
          duration: 30,
          timezone: "Central Time (US & Canada),America/Chicago",
          open_rsvps: true,
          legal_terms: true,
          recurring_mode: 'once',
          isUnstructuredRsvp: true,
          rsvp_slots: [{ instrument_id: "other", proficiency_level: 1, approve: true}]
      }
    }

    it "wide open scheduled session" do
      session = MusicSession.create(creator, open_params)
      session.valid?.should be_true
      # verify that scheduled_start is now 5 hours ahead of what was specified (CST during summer is -5 offset)
      session.scheduled_start.utc.should == DateTime.new(2014,07,11,3,00,0)

      # verify that the update_scheduled_start does not disturb scheduled_start
      session.save!
      session.scheduled_start.utc.should == DateTime.new(2014,07,11,3,00,0)
    end

    it "works with UTC timezone" do
      open_params[:timezone] = 'UTC,Etc/UTC'
      session = MusicSession.create(creator, open_params)
      session.valid?.should be_true
      # verify that scheduled_start is now 5 hours ahead of what was specified (CST during summer is -5 offset)
      session.scheduled_start.should == DateTime.new(2014,07,10,22,00,0)
    end

    it "no scheduled_start" do
      open_params[:timezone] = nil
      open_params[:scheduled_start] = nil
      open_params[:scheduled_duration] = nil
      session = MusicSession.create(creator, open_params)
      session.valid?.should be_true
      session.scheduled_start.should be_nil
    end
  end

  describe "pretty_scheduled_start" do
    it "displays central time correctly" do
      time = MusicSession.parse_scheduled_start("Thu Jul 10 2014 10:00 PM", "Central Time (US & Canada),America/Chicago")
      music_session = FactoryGirl.create(:music_session, scheduled_start: time, timezone: "Central Time (US & Canada),America/Chicago")
      music_session.pretty_scheduled_start(true).should == 'Thursday, July 10, 10:00-11:00 PM US Central Time'
      music_session.pretty_scheduled_start(false).should == 'Thursday, July 10 - 11:00pm'
    end

    it "displays default correctly" do
      music_session = FactoryGirl.create(:music_session, scheduled_start: nil)
      music_session.pretty_scheduled_start(true).should == 'Date and time TBD'
      music_session.pretty_scheduled_start(false).should == 'Date and time TBD'
    end

    it "displays default correctly (shorter)" do
      time = MusicSession.parse_scheduled_start("Thu Jul 10 2014 10:00 PM", "Central Time (US & Canada),America/Chicago")
      music_session = FactoryGirl.create(:music_session, scheduled_start: time, timezone: "Central Time (US & Canada),America/Chicago")
      puts music_session.pretty_scheduled_start(true, true)
      puts music_session.pretty_scheduled_start(true, false)
    end
  end

  describe "nindex" do
    it "nindex orders two sessions by created_at starting with most recent" do
      creator = FactoryGirl.create(:user)
      creator2 = FactoryGirl.create(:user)

      earlier_session = FactoryGirl.create(:active_music_session, :creator => creator, :description => "Earlier Session")
      c1 = FactoryGirl.create(:connection, user: creator, music_session: earlier_session, addr: 0x01020304, locidispid: 1)

      later_session = FactoryGirl.create(:active_music_session, :creator => creator2, :description => "Later Session")
      c2 = FactoryGirl.create(:connection, user: creator2, music_session: later_session, addr: 0x21020304, locidispid: 2)

      user = FactoryGirl.create(:user)
      c3 = FactoryGirl.create(:connection, user: user, locidispid: 3)

      Score.createx(c1.locidispid, c1.client_id, c1.addr, c3.locidispid, c3.client_id, c3.addr, 20, nil);
      Score.createx(c2.locidispid, c2.client_id, c2.addr, c3.locidispid, c3.client_id, c3.addr, 30, nil);

      # scores!

      #ActiveRecord::Base.logger = Logger.new(STDOUT)
      music_sessions = ActiveMusicSession.nindex(user, client_id: c3.client_id).take(100)
      #music_sessions = MusicSession.index(user).take(100)
      #ActiveRecord::Base.logger = nil

      music_sessions.length.should == 2
      music_sessions[0].id.should == later_session.id
      music_sessions[1].id.should == earlier_session.id
    end
  end


  it 'uninvited users cant join approval-required sessions without invitation' do
    user1 = FactoryGirl.create(:user) # in the jam session
    user2 = FactoryGirl.create(:user) # in the jam session

    music_session = FactoryGirl.create(:active_music_session, :creator => user1, :musician_access => true, :approval_required => true)

    connection1 = FactoryGirl.create(:connection, :user => user1, :music_session => music_session)
    expect { FactoryGirl.create(:connection, :user => user2, :music_session => music_session, :joining_session => true) }.to raise_error(ActiveRecord::RecordInvalid)

  end


  it "is_recording? returns false if not recording" do
    user1 = FactoryGirl.create(:user)
    music_session = FactoryGirl.build(:active_music_session, :creator => user1)
    music_session.is_recording?.should be_false
  end

  describe "recordings" do

    before(:each) do
      @user1 = FactoryGirl.create(:user)
      @connection = FactoryGirl.create(:connection, :user => @user1)
      @instrument = FactoryGirl.create(:instrument, :description => 'a great instrument')
      @track = FactoryGirl.create(:track, :connection => @connection, :instrument => @instrument)
      @music_session = FactoryGirl.create(:active_music_session, :creator => @user1, :musician_access => true)
      # @music_session.connections << @connection
      @music_session.save!
      @connection.join_the_session(@music_session, true, nil, @user1, 10)
    end

    describe "not recording" do
      it "stop_recording should return nil if not recording" do
        @music_session.stop_recording.should be_nil
      end
    end

    describe "currently recording" do
       before(:each) do
         @recording = FactoryGirl.create(:recording, :music_session => @music_session, :owner => @user1)
       end

       it "is_recording? returns true if recording" do
         @music_session.is_recording?.should be_true
       end

       it "stop_recording should return recording object if recording" do
         @music_session.stop_recording.should == @recording
       end
    end

    describe "claim a recording" do

      before(:each) do
        @recording = Recording.start(@music_session, @user1)
        @recording.errors.any?.should be_false
        @recording.stop
        @recording.reload
        @claimed_recording = @recording.claim(@user1, "name", "description", Genre.first, true)
        @claimed_recording.errors.any?.should be_false
      end

      it "allow a claimed recording to be associated" do
        @music_session.claimed_recording_start(@user1, @claimed_recording)
        @music_session.errors.any?.should be_false
        @music_session.reload
        @music_session.claimed_recording.should == @claimed_recording
        @music_session.claimed_recording_initiator.should == @user1
      end

      it "allow a claimed recording to be removed" do
        @music_session.claimed_recording_start(@user1, @claimed_recording)
        @music_session.errors.any?.should be_false
        @music_session.claimed_recording_stop
        @music_session.errors.any?.should be_false
        @music_session.reload
        @music_session.claimed_recording.should be_nil
        @music_session.claimed_recording_initiator.should be_nil
      end

      it "disallow a claimed recording to be started when already started by someone else" do
        @user2 = FactoryGirl.create(:user)
        @music_session.claimed_recording_start(@user1, @claimed_recording)
        @music_session.errors.any?.should be_false
        @music_session.claimed_recording_start(@user2, @claimed_recording)
        @music_session.errors.any?.should be_true
        @music_session.errors[:claimed_recording] == [ValidationMessages::CLAIMED_RECORDING_ALREADY_IN_PROGRESS]
      end

      it "allow a claimed recording to be started when already started by self" do
        @user2 = FactoryGirl.create(:user)
        @claimed_recording2 = @recording.claim(@user1, "name", "description", Genre.first, true)
        @music_session.claimed_recording_start(@user1, @claimed_recording)
        @music_session.errors.any?.should be_false
        @music_session.claimed_recording_start(@user1, @claimed_recording2)
        @music_session.errors.any?.should be_true
      end
    end
  end

  describe "get_connection_ids" do
    before(:each) do
      @user1 = FactoryGirl.create(:user)
      @user2 = FactoryGirl.create(:user)
      @music_session = FactoryGirl.create(:active_music_session, :creator => @user1, :musician_access => true)
      @connection1 = FactoryGirl.create(:connection, :user => @user1, :music_session => @music_session, :as_musician => true)
      @connection2 = FactoryGirl.create(:connection, :user => @user2, :music_session => @music_session, :as_musician => false)

    end

    it "get all connections" do
      @music_session.get_connection_ids().should == [@connection1.client_id, @connection2.client_id]
    end

    it "exclude non-musicians" do
      @music_session.get_connection_ids(as_musician: true).should == [@connection1.client_id]
    end

    it "exclude musicians" do
      @music_session.get_connection_ids(as_musician: false).should == [@connection2.client_id]
    end

    it "exclude particular client" do
      @music_session.get_connection_ids(exclude_client_id: @connection1.client_id).should == [@connection2.client_id]
    end

    it "exclude particular client and exclude non-musicians" do
      @music_session.get_connection_ids(exclude_client_id: @connection2.client_id, as_musician: true).should == [@connection1.client_id]
    end
  end

  describe "approved_rsvps" do
    it "aggregrates instrument info" do

      creators_slot = music_session1.rsvp_slots[0]
      music_session1.approved_rsvps.length.should == 1
      approved_user = music_session1.approved_rsvps[0]
      approved_user[:instrument_ids][0].should == creators_slot.instrument.id
      approved_user[:instrument_descriptions][0].should == creators_slot.instrument.description
      approved_user[:instrument_proficiencies][0].should == creators_slot.proficiency_level
      approved_user[:rsvp_request_ids][0].should == creators_slot.rsvp_requests[0].id

    end

    it "unstructured rsvps should still be returned" do
      music_session1.rsvp_slots.length.should == 1
      creators_slot = music_session1.rsvp_slots[0]

      # now take out the instrument and proficiency of the rsvp_slot (make it unstructured)
      creators_slot.is_unstructured_rsvp = true
      creators_slot.instrument = nil
      creators_slot.proficiency_level = nil
      creators_slot.save!

      music_session = MusicSession.find(music_session1.id)
      approved_rsvps = music_session.approved_rsvps
      approved_rsvps.length.should == 1
      approved_user = approved_rsvps[0]
      approved_user[:instrument_ids][0].should == nil
      approved_user[:instrument_descriptions][0].should == nil
      approved_user[:instrument_proficiencies][0].should == nil
      approved_user[:rsvp_request_ids][0].should == creators_slot.rsvp_requests[0].id
    end

    it "handles 2 instruments for a single request correctly" do

      rsvp_request = FactoryGirl.create(:rsvp_request_for_multiple_slots, user: some_user, music_session: music_session1, number: 2, chosen:true)

      approved_rsvps = music_session1.approved_rsvps
      approved_rsvps.length.should == 2

      # find the user who made the request for 2 rsvp slots in the approved_users array
      approved_some_user = approved_rsvps.find {|s| s.id == some_user.id}

      instrument_ids = approved_some_user[:instrument_ids]
      instrument_ids.should =~ rsvp_request.rsvp_slots.map {|slot| slot.instrument_id }

      instrument_descriptions = approved_some_user[:instrument_descriptions]
      instrument_descriptions.should =~ rsvp_request.rsvp_slots.map {|slot| slot.instrument.description }
      instrument_proficiencies = approved_some_user[:instrument_proficiencies]
      instrument_proficiencies.should =~ rsvp_request.rsvp_slots.map {|slot| slot.proficiency_level }
      approved_some_user[:rsvp_request_ids][0].should == rsvp_request.id

    end
  end

  describe "parse_scheduled_start" do

    it "converts central time correctly" do

      # CST has -5 offset in summery
      time = DateTime.new(2004,10,15,1,30,0).strftime('%Y-%m-%d %H:%M:%S')
      converted = MusicSession.parse_scheduled_start(time, 'Central Time (US & Canada),America/Chicago')
      converted.should == DateTime.new(2004,10,15,6,30,0, '+0')

      # CST has -6 offset in winter
      time = DateTime.new(2004,11,15,1,30,0).strftime('%Y-%m-%d %H:%M:%S')
      converted = MusicSession.parse_scheduled_start(time, 'Central Time (US & Canada),America/Chicago')
      converted.should == DateTime.new(2004,11,15,7,30,0, '+0')
    end

    it "converts UTC correctly" do
      # should not shift
      time = DateTime.new(2004,10,15,1,30,0, '+0').strftime('%Y-%m-%d %H:%M:%S')
      converted = MusicSession.parse_scheduled_start(time, 'UTC,Etc/UTC')
      converted.should == DateTime.new(2004,10,15,1,30,0, '+0')

      # should not shift
      time = DateTime.new(2004,11,15,1,30,0).strftime('%Y-%m-%d %H:%M:%S')
      converted = MusicSession.parse_scheduled_start(time, 'UTC,Etc/UTC')
      converted.should == DateTime.new(2004,11,15,1,30,0, '+0')
    end

  end

  describe "scheduled" do

    it "includes any RSVP'ed" do
      rsvp_request = FactoryGirl.create(:rsvp_request_for_multiple_slots, user: some_user, music_session: music_session1, number: 2, chosen:true)

      approved_rsvps = music_session1.approved_rsvps
      approved_rsvps.length.should == 2


      sessions = MusicSession.scheduled(User.find(approved_rsvps[0].id))
      sessions.each do |session|
        puts session.name
        puts session.description
      end

      sessions.length.should == 1

      sessions = MusicSession.scheduled(User.find(approved_rsvps[1].id))
      sessions.length.should == 1
    end

    it "includes invited" do
      invitee = FactoryGirl.create(:user, last_jam_audio_latency: 30, last_jam_locidispid: 3)
      FactoryGirl.create(:friendship, user: creator, friend: invitee)
      FactoryGirl.create(:friendship, user: invitee, friend: creator)
      music_session = FactoryGirl.create(:music_session, creator: creator)
      FactoryGirl.create(:invitation, receiver:invitee, sender:creator, music_session: music_session)

      sessions = MusicSession.scheduled(invitee)
      sessions.length.should == 1
    end
    it "excludes based on time-range" do
      session = FactoryGirl.create(:music_session, scheduled_start: Time.now)

      MusicSession.count.should eq(1)

      sessions = MusicSession.scheduled(session.creator)
      sessions.length.should == 1

      session.scheduled_start = 11.hours.ago
      session.save!
      sessions = MusicSession.scheduled(session.creator)
      sessions.length.should == 1

      session.scheduled_start = 13.hours.ago
      session.save!

      session.reload
      session.session_removed_at.should be_nil
      sessions = MusicSession.scheduled(session.creator)
      sessions.count.should == 0

      session.scheduled_start = 13.hours.from_now
      session.save!
      sessions = MusicSession.scheduled(session.creator)
      sessions.length.should == 1

      session.scheduled_start = 300.days.from_now
      session.save!
      sessions = MusicSession.scheduled(session.creator)
      sessions.length.should == 1

      session.scheduled_start = nil
      session.save!
      sessions = MusicSession.scheduled(session.creator)
      sessions.length.should == 1
    end

    it "excludes canceled" do
      session = FactoryGirl.create(:music_session, scheduled_start: Time.now)
      sessions = MusicSession.scheduled(session.creator)
      sessions.length.should == 1

      session.canceled = true
      session.save!
      MusicSession.scheduled(session.creator).length.should == 0
    end
  end

  def sms(user, params)
    ActiveRecord::Base.transaction do
      return MusicSession.sms_index(user, params)
    end
  end


  def sms(user, params, assert_music_sessions_length = nil, assert_user_scores_length = nil)
    ActiveRecord::Base.transaction do
      music_sessions, user_scores = MusicSession.sms_index(user, params)

      music_sessions.length.should eq(assert_music_sessions_length) if assert_music_sessions_length
      user_scores.length.should eq(assert_user_scores_length) if assert_user_scores_length

      return music_sessions, user_scores
    end
  end

  def session_with_scores(user, music_session_id)
    ActiveRecord::Base.transaction do
      return MusicSession.session_with_scores(user, music_session_id)
    end
  end

  describe "session_with_scores", no_transaction: true do
    let(:conn) { FactoryGirl.create(:connection, user: creator, locidispid: creator.last_jam_locidispid) }
    let(:searcher) { FactoryGirl.create(:user, last_jam_locidispid: 2) }
    let(:searcher_conn) { FactoryGirl.create(:connection, user: searcher, ip_address: '2.2.2.2', locidispid: searcher.last_jam_locidispid) }
    let(:default_opts) { {client_id: searcher_conn.client_id} }
    let(:network_score) { 20 }

    before(:each) do
      Score.createx(conn.locidispid, conn.client_id, conn.addr, searcher_conn.locidispid, searcher_conn.client_id, searcher_conn.addr, network_score, nil, nil, {auserid: creator.id, buserid: searcher.id})
    end

    it "invalid session ID" do
      expect {session_with_scores(searcher, 'blah')}.to raise_error(ActiveRecord::RecordNotFound)
    end

    it "one session with scores" do
      session = FactoryGirl.create(:music_session, creator: creator)
      music_session, user_scores = session_with_scores(searcher, session.id)
      music_session.latency.should be_nil # we don't return music_session.latency with session_with_scores, because it's used for sorting among many sessions
      user_scores.length.should == 1
      user_scores[creator.id][:full_score].should == (network_score + searcher.last_jam_audio_latency + creator.last_jam_audio_latency )
    end
  end

  describe "sms_index_2" do
    describe "simple" do
      let(:conn) { FactoryGirl.create(:connection, user: creator, locidispid: creator.last_jam_locidispid) }
      let(:searcher) { FactoryGirl.create(:user, last_jam_locidispid: 2) }
      let(:searcher_conn) { FactoryGirl.create(:connection, user: searcher, ip_address: '2.2.2.2', locidispid: searcher.last_jam_locidispid) }
      let(:default_opts) { {client_id: searcher_conn.client_id} }
      let(:network_score) { 20 }

      it "no results" do
        music_sessions = MusicSession.scheduled_index(searcher, {})
      end

      it "one session shows/hides based on open_rsvps" do

        music_session = FactoryGirl.create(:music_session, creator: creator, scheduled_start: nil)
        music_sessions = MusicSession.scheduled_index(searcher, {})
        music_sessions.length.should == 1

        music_session.open_rsvps = false
        music_session.save!
        music_sessions = MusicSession.scheduled_index(searcher, {})
        music_sessions.length.should == 0
      end


      it "one session, one RSVP (creator)" do
        music_session = FactoryGirl.create(:music_session, creator: creator)
        music_sessions = MusicSession.scheduled_index(searcher, {})
        music_sessions.length.should == 1
      end

      it "skip session with past due scheduled_start time" do
        interval = MusicSession::UNSTARTED_INTERVAL_DAYS_SKIP
        dd = Time.now - (interval.to_i + 1).days
        Timecop.travel(dd)
        msess1 = FactoryGirl.create(:music_session, creator: creator, scheduled_start: dd)
        msess2 = FactoryGirl.create(:music_session, creator: creator)
        music_sessions = MusicSession.scheduled_index(searcher, {})
        music_sessions.length.should == 1
        expect(music_sessions[0].id).to eq(msess2.id)
      end

      it "filters sessions in the past" do

        music_session = FactoryGirl.create(:music_session, creator: creator)
        music_sessions = MusicSession.scheduled_index(searcher, {})
        music_sessions.length.should == 1

        # 15 minutes is the edge of forgiveness
        music_session.scheduled_start = 16.minutes.ago
        music_session.save!

        music_sessions  = MusicSession.scheduled_index(searcher, {})
        music_sessions.length.should == 0

        # this should still fall in time
        music_session.scheduled_start = 14.minutes.ago
        music_session.save!

        music_sessions = MusicSession.scheduled_index(searcher, {})
        music_sessions.length.should == 1
      end

      it "one session, one RSVP (creator), one invitation" do
        # create an invitee, and friend them with the creator (you have to be friends to send an invite)
        invitee = FactoryGirl.create(:user)
        FactoryGirl.create(:friendship, user: creator, friend: invitee)
        FactoryGirl.create(:friendship, user: invitee, friend: creator)
        music_session = FactoryGirl.create(:music_session, creator: creator)
        FactoryGirl.create(:invitation, receiver:invitee, sender:creator, music_session: music_session)

        music_sessions  = MusicSession.scheduled_index(searcher, default_opts)
        music_sessions.length.should == 1

        #search with the invitee this time.
        invitee_conn = FactoryGirl.create(:connection, user: invitee)
        music_sessions = MusicSession.scheduled_index(invitee, {})
        music_sessions.length.should == 1
      end

      it "does not show when it goes active" do
        # we create a scheduled session--it should return
        music_session = FactoryGirl.create(:music_session, creator: creator, scheduled_start: nil)
        music_sessions = MusicSession.scheduled_index(searcher, {})
        music_sessions.length.should == 1

        # but then make an active session for this scheduled session
        ams = FactoryGirl.create(:active_music_session, music_session: music_session, creator: creator, musician_access: true)
        music_sessions = MusicSession.scheduled_index(searcher, {})
        music_sessions.length.should == 0

        # finally, delete the active session, and see results go back to one
        ams.delete
        music_sessions = MusicSession.scheduled_index(searcher, {})
        music_sessions.length.should == 1
      end
    end

  end
  describe "sms_index", no_transaction: true do

    describe "simple" do
      let(:conn) { FactoryGirl.create(:connection, user: creator, locidispid: creator.last_jam_locidispid) }
      let(:searcher) { FactoryGirl.create(:user, last_jam_locidispid: 2) }
      let(:searcher_conn) { FactoryGirl.create(:connection, user: searcher, ip_address: '2.2.2.2', locidispid: searcher.last_jam_locidispid) }
      let(:default_opts) { {client_id: searcher_conn.client_id} }
      let(:network_score) { 20 }

      before(:each) do
        pending "Update to use MusicSession.scheduled_index"
        Score.createx(conn.locidispid, conn.client_id, conn.addr, searcher_conn.locidispid, searcher_conn.client_id, searcher_conn.addr, network_score, nil, nil, {auserid: creator.id, buserid: searcher.id})
      end

      it "no results" do
        music_sessions, user_scores = sms(searcher, default_opts, 0, 0)
      end

      it "one session shows/hides based on open_rsvps" do
        creator.last_jam_locidispid = conn.locidispid
        creator.save!

        music_session = FactoryGirl.create(:music_session, creator: creator, scheduled_start: nil)
        music_sessions, user_scores = sms(searcher, default_opts, 1)

        music_session.open_rsvps = false
        music_session.save!
        music_sessions, user_scores = sms(searcher, default_opts, 0)
      end

      it "one session with no scheduled_start time" do
        creator.last_jam_locidispid = conn.locidispid
        creator.save!

        music_session = FactoryGirl.create(:music_session, creator: creator, scheduled_start: nil)
        music_sessions, user_scores = sms(searcher, default_opts, 1)
      end


      it "one session, one RSVP (creator)" do
        creator.last_jam_locidispid = conn.locidispid
        creator.save!

        music_session = FactoryGirl.create(:music_session, creator: creator)
        music_sessions, user_scores = sms(searcher, default_opts, 1, 1)
        music_sessions[0].tag.should == 3 # open session sort
        music_sessions[0].latency.should == (network_score + searcher.last_jam_audio_latency + creator.last_jam_audio_latency )
        user_scores[creator.id][:full_score].should == (network_score + searcher.last_jam_audio_latency + creator.last_jam_audio_latency )
      end

      it "skip session with past due scheduled_start time" do
        interval = MusicSession::UNSTARTED_INTERVAL_DAYS_SKIP
        dd = Time.now - (interval.to_i + 1).days
        Timecop.travel(dd)    
        msess1 = FactoryGirl.create(:music_session, creator: creator, scheduled_start: dd)
        msess2 = FactoryGirl.create(:music_session, creator: creator)
        music_sessions, user_scores = sms(searcher, default_opts, 1)
        expect(music_sessions[0].id).to eq(msess2.id)
      end

      it "filters sessions in the past" do

        music_session = FactoryGirl.create(:music_session, creator: creator)
        ActiveRecord::Base.transaction do
          music_sessions, user_scores = sms(searcher, default_opts, 1)
        end

        # 15 minutes is the edge of forgiveness
        music_session.scheduled_start = 16.minutes.ago
        music_session.save!

        music_sessions, user_scores = sms(searcher, default_opts, 0)

        # this should still fall in time
        music_session.scheduled_start = 14.minutes.ago
        music_session.save!

        music_sessions, user_scores = sms(searcher, default_opts, 1)
      end

      it "one session, one RSVP (creator), one invitation" do
        # create an invitee, and friend them with the creator (you have to be friends to send an invite)
        invitee = FactoryGirl.create(:user, last_jam_audio_latency: 30, last_jam_locidispid: 3)
        FactoryGirl.create(:friendship, user: creator, friend: invitee)
        FactoryGirl.create(:friendship, user: invitee, friend: creator)
        music_session = FactoryGirl.create(:music_session, creator: creator)
        FactoryGirl.create(:invitation, receiver:invitee, sender:creator, music_session: music_session)

        # create a score between creator, searcher
        Score.createx(creator.last_jam_locidispid, conn.client_id, conn.addr, searcher.last_jam_locidispid, searcher_conn.client_id, searcher_conn.addr, network_score, nil, nil, {auserid: creator.id, buserid: searcher.id})
        # create a score between invitee, and searcher
        Score.createx(invitee.last_jam_locidispid, 'immaterial', 1, searcher.last_jam_locidispid, searcher_conn.client_id, searcher_conn.addr, network_score, nil, nil, {auserid: invitee.id, buserid: searcher.id})
        # create a score between invitee, and creator
        Score.createx(invitee.last_jam_locidispid, 'immaterial', 1, creator.last_jam_locidispid, conn.client_id, conn.addr, network_score, nil, nil)

        music_sessions, user_scores = sms(searcher, default_opts, 1, 1)
        music_sessions[0].tag.should == 3 # open session sort
        music_sessions[0].latency.should == (network_score + searcher.last_jam_audio_latency + creator.last_jam_audio_latency )
        user_scores[creator.id][:full_score].should == (network_score + searcher.last_jam_audio_latency + creator.last_jam_audio_latency )

        #search with the invitee this time.
        invitee_conn = FactoryGirl.create(:connection, user: invitee, ip_address: '3.3.3.3', locidispid: invitee.last_jam_locidispid)
        music_sessions, user_scores = sms(invitee, {client_id: invitee_conn.client_id}, 1, 1)
        music_sessions[0].tag.should == 2 # invited sort
        music_sessions[0].latency.should == ((network_score + invitee.last_jam_audio_latency + creator.last_jam_audio_latency )).ceil
        user_scores[creator.id][:full_score].should == ((network_score + invitee.last_jam_audio_latency + creator.last_jam_audio_latency )).ceil
      end

      it "does not show when it goes active" do
        # we create a scheduled session--it should return
        music_session = FactoryGirl.create(:music_session, creator: creator, scheduled_start: nil)
        music_sessions, user_scores = sms(searcher, default_opts, 1)

        # but then make an active session for this scheduled session
        ams = FactoryGirl.create(:active_music_session, music_session: music_session, creator: creator, musician_access: true)
        music_sessions, user_scores = sms(searcher, default_opts, 0)

        # finally, delete the active session, and see results go back to one
        ams.delete
        music_sessions, user_scores = sms(searcher, default_opts, 1)
      end

      it "should allow a null locidispid to search" do
        searcher_conn.locidispid = nil
        searcher_conn.save!
        music_sessions, user_scores = sms(searcher, default_opts, 0)
      end

      describe "keywords" do
        before(:each) do
          creator.last_jam_locidispid = conn.locidispid
          creator.save!
          FactoryGirl.create(:music_session, creator: creator, scheduled_start: nil, description: 'chunky icecream for the fools')
        end

        it "handles single keyword" do
          default_opts[:keyword] = 'chunky'
          music_sessions, user_scores = sms(searcher, default_opts, 1, 1)
        end

        it "handles two keyword" do
          default_opts[:keyword] = 'chunky for'
          music_sessions, user_scores = sms(searcher, default_opts, 1, 1)
        end

        it "handles single quote" do
          default_opts[:keyword] = "chun'ky fo'r"
          music_sessions, user_scores = sms(searcher, default_opts, 0, 1)

          default_opts[:keyword] = "chunky for'"
          music_sessions, user_scores = sms(searcher, default_opts, 1, 1)
        end
      end
    end


    describe "sorting" do
      let!(:creator_1) { FactoryGirl.create(:user, last_jam_locidispid: 4, last_jam_audio_latency: 8) }
      let!(:creator_conn_1) { FactoryGirl.create(:connection, user: creator_1, ip_address: '4.4.4.4', locidispid: 4, addr:4) }
      let!(:creator_2) { FactoryGirl.create(:user, last_jam_locidispid: 1, last_jam_audio_latency: 10) }
      let!(:creator_conn_2) { FactoryGirl.create(:connection, user: creator_2, ip_address: '4.4.4.4', locidispid: 1, addr:1) }
      let!(:creator_3) { FactoryGirl.create(:user, last_jam_locidispid: 2, last_jam_audio_latency: 12) }
      let!(:creator_conn_3) { FactoryGirl.create(:connection, user: creator_3, ip_address: '5.5.5.5', locidispid: 2, addr:2) }
      let!(:searcher_1) { FactoryGirl.create(:user, last_jam_locidispid: 5, last_jam_audio_latency: 6) }
      let!(:searcher_conn_1) { FactoryGirl.create(:connection, user: searcher_1, ip_address: '8.8.8.8', locidispid: 5, addr:5) }
      let!(:searcher_2) { FactoryGirl.create(:user, last_jam_locidispid: 3, last_jam_audio_latency: 14) }
      let!(:searcher_conn_2) { FactoryGirl.create(:connection, user: searcher_2, ip_address: '9.9.9.9', locidispid: 3, addr:3) }

      let!(:music_session_1) { FactoryGirl.create(:music_session, creator: creator_1, genre: Genre.find('african'), language: 'eng', description: "Bunny Jumps") }
      let!(:music_session_2) { FactoryGirl.create(:music_session, creator: creator_2, genre: Genre.find('ambient'), language: 'spa', description: "Play with us as we jam to beatles and bunnies") }
      let!(:music_session_3) { FactoryGirl.create(:music_session, creator: creator_3) }

      let(:good_network_score) { 20 }
      let(:fair_network_score) { 30 }
      let(:bad_network_score)  { 40 }

      before(:each) do

        pending "Test with MusicSession.scheduled_index instsead"

        # add an RSVP for searcher_1 to music_session_1
        searcher_rsvp_slot = FactoryGirl.create(:rsvp_slot, music_session: music_session_1, instrument: Instrument.find('piano'))
        searcher_rsvp_request = FactoryGirl.create(:rsvp_request, user: searcher_1)
        searcher_rsvp_request_rsvp_slot = FactoryGirl.create(:rsvp_request_rsvp_slot, chosen:true, rsvp_request: searcher_rsvp_request, rsvp_slot: searcher_rsvp_slot)

        # add an invitation to searcher_1 to music_session_2
        FactoryGirl.create(:friendship, user: creator_2, friend: searcher_1)
        FactoryGirl.create(:friendship, user: searcher_1, friend: creator_2)
        FactoryGirl.create(:invitation, receiver:searcher_1, sender:creator_2, music_session: music_session_2)

      end


      it "searcher_1" do

        # create a bad score between searcher_1 and creator_1 (but we should still see it sort 1st because it's got an RSVP to the searcher)
        Score.createx(searcher_conn_1.locidispid, searcher_conn_1.client_id, searcher_conn_1.addr, creator_conn_1.locidispid, creator_conn_1.client_id, creator_conn_1.addr, bad_network_score, nil, nil, {auserid: searcher_1.id, buserid: creator_1.id})

        # create a fair score between searcher_1 and creator_2 (but we should still see it sort 2st because it's got an invitation to the searcher)
        Score.createx(searcher_conn_1.locidispid, searcher_conn_1.client_id, searcher_conn_1.addr, creator_conn_2.locidispid, creator_conn_2.client_id, creator_conn_2.addr, fair_network_score, nil, nil, {auserid: searcher_1.id, buserid: creator_2.id})

        # create a good score between searcher_1 and creator_3 (but we should still see it sort last because it's an open session; no affiliation with the searcher)
        Score.createx(searcher_conn_1.locidispid, searcher_conn_1.client_id, searcher_conn_1.addr, creator_conn_3.locidispid, creator_conn_3.client_id, creator_conn_3.addr, good_network_score, nil, nil, {auserid: searcher_1.id, buserid: creator_3.id})

        music_sessions, user_scores = sms(searcher_1, {client_id: searcher_conn_1.client_id}, 3, 3)

        music_session = music_sessions[0]
        music_session.should == music_session_1
        music_session.tag.should == 1 # RSVP
        music_session.latency.should ==  (bad_network_score + searcher_1.last_jam_audio_latency + creator_1.last_jam_audio_latency )

        music_session = music_sessions[1]
        music_session.should == music_session_2
        music_session.tag.should == 2 # INVITE
        music_session.latency.should ==  (fair_network_score + searcher_1.last_jam_audio_latency + creator_2.last_jam_audio_latency )

        music_session = music_sessions[2]
        music_session.should == music_session_3
        music_session.tag.should == 3 # OPEN
        music_session.latency.should ==  (good_network_score + searcher_1.last_jam_audio_latency + creator_3.last_jam_audio_latency )

        user_scores[creator_1.id][:full_score].should == (bad_network_score + searcher_1.last_jam_audio_latency + creator_1.last_jam_audio_latency )

        # let's make music_session_3 invisible, and verify the count goes to 2
        music_session_3.open_rsvps = false
        music_session_3.save!
        music_sessions, user_scores = sms(searcher_1, {client_id: searcher_conn_1.client_id}, 2)

        # let's make music_session_2 invisible, but still the count should be the same (because searcher_1 have an invite)
        music_session_2.open_rsvps = false
        music_session_2.save!
        music_sessions, user_scores = sms(searcher_1, {client_id: searcher_conn_1.client_id}, 2)

        # and lastly with music_session_1, make it invisible, and still it should be visible to the searcher (because searcher_1 has an invite)
        music_session_1.open_rsvps = false
        music_session_1.save!
        music_sessions, user_scores = sms(searcher_1, {client_id: searcher_conn_1.client_id}, 2)
      end
    end

    describe "parameters" do
      let(:creator_1) { FactoryGirl.create(:user, last_jam_locidispid: 4, last_jam_audio_latency: 8) }
      let(:creator_conn_1) { FactoryGirl.create(:connection, user: creator_1, ip_address: '4.4.4.4', locidispid: 4, addr:4) }
      let(:creator_2) { FactoryGirl.create(:user, last_jam_locidispid: 1, last_jam_audio_latency: 10) }
      let(:creator_conn_2) { FactoryGirl.create(:connection, user: creator_2, ip_address: '4.4.4.4', locidispid: 1, addr:1) }
      let(:creator_3) { FactoryGirl.create(:user, last_jam_locidispid: 2, last_jam_audio_latency: 12) }
      let(:creator_conn_3) { FactoryGirl.create(:connection, user: creator_3, ip_address: '5.5.5.5', locidispid: 2, addr:2) }
      let(:searcher_1) { FactoryGirl.create(:user, last_jam_locidispid: 5, last_jam_audio_latency: 6) }
      let(:searcher_conn_1) { FactoryGirl.create(:connection, user: searcher_1, ip_address: '8.8.8.8', locidispid: 5, addr:5) }
      let(:searcher_2) { FactoryGirl.create(:user, last_jam_locidispid: 3, last_jam_audio_latency: 14) }
      let(:searcher_conn_2) { FactoryGirl.create(:connection, user: searcher_2, ip_address: '9.9.9.9', locidispid: 3, addr:3) }

      let!(:music_session_1) { FactoryGirl.create(:music_session, :creator => creator_1, genre: Genre.find('african'), language: 'eng', description: "Bunny Jumps" ) }
      let!(:music_session_2) { FactoryGirl.create(:music_session, :creator => creator_2, genre: Genre.find('ambient'), language: 'spa', description: "Play with us as we jam to beatles and bunnies") }

      let(:good_network_score) { 20 }
      let(:fair_network_score) { 30 }

      before {
        pending "Test with MusicSession.scheduled_index instsead"
      }

      it "offset/limit" do
        # set up some scores to control sorting
        Score.createx(searcher_conn_1.locidispid, searcher_conn_1.client_id, searcher_conn_1.addr, creator_conn_1.locidispid, creator_conn_1.client_id, creator_conn_1.addr, good_network_score, nil)
        Score.createx(searcher_conn_1.locidispid, searcher_conn_1.client_id, searcher_conn_1.addr, creator_conn_2.locidispid, creator_conn_2.client_id, creator_conn_2.addr, fair_network_score, nil)

        # verify we can get all 2 sessions
        music_sessions, user_search = sms(searcher_1, { client_id: searcher_conn_1.client_id }, 2)
        music_sessions[0].should == music_session_1

        # grab just the 1st
        music_sessions, user_search = sms(searcher_1, { client_id: searcher_conn_1.client_id, offset:0, limit:1}, 1)
        music_sessions[0].should == music_session_1

        # then the second
        music_sessions, user_search = sms(searcher_1, {client_id: searcher_conn_1.client_id, offset:1, limit:2}, 1)
        music_sessions[0].should == music_session_2
      end

      it "genre" do
        # verify we can get all 2 sessions
        music_sessions, user_search = sms(searcher_1, { client_id: searcher_conn_1.client_id}, 2)

        # get only african
        music_sessions, user_search = sms(searcher_1, {client_id: searcher_conn_1.client_id, genre: 'african'}, 1)
        music_sessions[0].genre.should == Genre.find('african')

        # get only ambient
        music_sessions, user_search = sms(searcher_1, {client_id: searcher_conn_1.client_id, genre: 'ambient'}, 1)
        music_sessions[0].genre.should == Genre.find('ambient')
      end

      it "language" do
        # verify we can get all 2 sessions
        music_sessions, user_search = sms(searcher_1, { client_id: searcher_conn_1.client_id}, 2)

        # get only english
        music_sessions, user_search = sms(searcher_1, {client_id: searcher_conn_1.client_id, lang: 'eng'}, 1)
        music_sessions[0].language.should == 'eng'

        # get only ambient
        music_sessions, user_search = sms(searcher_1, { client_id: searcher_conn_1.client_id, lang: 'spa'}, 1)
        music_sessions[0].language.should == 'spa'
      end

      it "keyword" do
        music_sessions, user_search = sms(searcher_1, { client_id: searcher_conn_1.client_id, keyword: 'Jump' }, 1)
        music_sessions[0].should == music_session_1

        music_sessions, user_search = sms(searcher_1, { client_id: searcher_conn_1.client_id, keyword: 'Bunny'}, 2)

        music_sessions, user_search = sms(searcher_1, { client_id: searcher_conn_1.client_id, keyword: 'play' }, 1)

        music_sessions, user_search = sms(searcher_1, { client_id: searcher_conn_1.client_id, keyword: 'bun' } , 2)
      end

      it "date" do
        music_session_1.scheduled_start = 1.days.ago
        music_session_1.save!

        # if no day/timezone_offset specified, then the 15 minute slush rule will still kick in, nixing music_session_1
        music_sessions, user_search = sms(searcher_1, {client_id: searcher_conn_1.client_id}, 1)
        music_sessions[0].should == music_session_2

        # find today's session
        music_sessions, user_search = sms(searcher_1, {client_id: searcher_conn_1.client_id, day: Date.today.to_s, timezone_offset: DateTime.now.offset.numerator}, 1)
        music_sessions[0].should == music_session_2

        # find yesterday's session... oh wait, you can't find a session for yesterday, because the 15 minute slush rule will still kick in.
        music_sessions, user_search = sms(searcher_1, {client_id: searcher_conn_1.client_id, day: (Date.today - 1).to_s, timezone_offset: DateTime.now.offset.numerator}, 0)

        # but let's make it tomorrow, so we can test in that direction
        music_session_1.scheduled_start = 1.day.from_now
        music_session_1.save!

        music_sessions, user_search = sms(searcher_1, {client_id: searcher_conn_1.client_id, day: (Date.today + 1).to_s, timezone_offset: DateTime.now.offset.numerator}, 1)
        music_sessions[0].should == music_session_1
      end
    end


    describe "scheduled_rsvp" do

      let(:creator_1) { FactoryGirl.create(:user) }
      let!(:music_session_1) { FactoryGirl.create(:music_session, :creator => creator_1, description: "Bunny Jumps", :create_type => MusicSession::CREATE_TYPE_IMMEDIATE ) }
      let!(:music_session_2) { FactoryGirl.create(:music_session, :creator => FactoryGirl.create(:user), description: "Bunny Jumps", :create_type => MusicSession::CREATE_TYPE_IMMEDIATE ) }

      before(:each) {
        music_session_2.touch
      }
      it "lists one" do
        MusicSession.scheduled_rsvp(creator_1).should == [music_session_1]
      end

      it "does not list canceled" do
        music_session_1.canceled = true
        music_session_1.save!
        MusicSession.scheduled_rsvp(creator_1).should == []
      end

      it "does not list old" do
        music_session_1.scheduled_start = 5.hours.ago
        music_session_1.save!
        MusicSession.scheduled_rsvp(creator_1).should == []
      end

      it "only show approved sessions" do
        MusicSession.scheduled_rsvp(creator_1, true).should == [music_session_1]
      end

      it "does not show unchosen" do
        music_session_1.rsvp_slots[0].rsvp_requests_rsvp_slots[0].chosen = false
        music_session_1.rsvp_slots[0].rsvp_requests_rsvp_slots[0].save!
        MusicSession.scheduled_rsvp(creator_1, true).should == []
      end

      it "create_type = nil will still return RSVPs" do
        music_session_1.create_type = nil
        music_session_1.save!

        MusicSession.scheduled_rsvp(creator_1, true).should == [music_session_1]
      end
    end
  end

  describe "scheduled session rescheduled logic" do

    it "detect change to scheduling info" do

      music_session1.description = "Hey!"
      music_session1.save!
      music_session1.scheduling_info_changed.should be_false

      music_session1.scheduled_start = Time.now - 1.days
      music_session1.save!
      music_session1.scheduling_info_changed.should be_true

    end
  end

  describe "html_sanitize" do
    it "sanitizes" do
      music_session1.name = '<b>dog</b>'
      music_session1.description = '<html>cat</html>'
      music_session1.save!
      music_session1.name.should == 'dog'
      music_session1.description.should == 'cat'
    end
  end

  describe "purgeable sessions" do

    it 'selects unscheduled sessions past due date' do
      interval = MusicSession::UNSTARTED_INTERVAL_DAYS_PURGE
      msess1 = FactoryGirl.create(:music_session)
      dd = Time.now - (interval.to_i + 1).days
      Timecop.travel(dd)
      msess2 = FactoryGirl.create(:music_session)
      purging = MusicSession.purgeable_sessions
      expect(purging.size).to be(1)
      expect(purging[0].id).to eq(msess2.id)
    end

    it 'selects recurring and non-recurring sessions past due date' do
      [MusicSession::UNSTARTED_INTERVAL_DAYS_PURGE, 
       MusicSession::UNSTARTED_INTERVAL_DAYS_PURGE_RECUR].each do |interval|
        Timecop.return
        msess1 = FactoryGirl.create(:music_session, scheduled_start: Time.now)
        dd = Time.now - (interval.to_i + 1).days
        Timecop.travel(dd)    
        msess2 = FactoryGirl.create(:music_session, scheduled_start: Time.now)
        purging = MusicSession.purgeable_sessions
        expect(purging.size).to be(1)
        expect(purging[0].id).to eq(msess2.id)
        MusicSession.delete_all
      end
    end
  end

end

