require 'spec_helper'
require 'webmock/rspec'

describe MusicianFilter do
  let(:latency_data_uri) { /\S+\/search_users/ }
  let(:user) { FactoryGirl.create(:user) }
  let(:remote_ip) { "127.0.0.1" }

  let(:user1) { FactoryGirl.create(:user) }
  let(:user2) { FactoryGirl.create(:user) }
  let(:user3) { FactoryGirl.create(:user) }
  let(:user4) { FactoryGirl.create(:user) }
  let(:user5) { FactoryGirl.create(:user) }
  let(:user6) { FactoryGirl.create(:user) }
  let(:user7) { FactoryGirl.create(:user) }
  let(:user8) { FactoryGirl.create(:user) }

  let(:response_body) { mock_latency_response([
    { user: user1, ars_total_latency: 1.0, ars_internet_latency: 0.4, audio_latency: 0.6 }, #GOOD
    { user: user2, ars_total_latency: 40.0, ars_internet_latency: 25.0, audio_latency: 15.0 }, #GOOD
    { user: user3, ars_total_latency: 40.1, ars_internet_latency: 25, audio_latency: 15.1 }, #FAIR
    { user: user4, ars_total_latency: 60.0, ars_internet_latency: 30, audio_latency: 30.0 }, #FAIR
    { user: user5, ars_total_latency: 60.1, ars_internet_latency: 30.1, audio_latency: 30 }, #HIGH
    { user: user6, ars_total_latency: 100.0, ars_internet_latency: 50.0, audio_latency: 50.0 }, #HIGH
    { user: user7, ars_total_latency: -2, ars_internet_latency: -1, audio_latency: -1 }, #UNKNOWN
    { user: user8, ars_total_latency: 10, ars_internet_latency: 5, audio_latency: 0 } #GOOD (NOTE: audio_latency from neo4j is 0 here)
    ])
  }

  let(:response_body_pop) { mock_latency_response([
    { user: user1, ars_total_latency: 1.0, ars_internet_latency: 0.4, audio_latency: 0.6 }, #GOOD
    { user: user2, ars_total_latency: 40.0, ars_internet_latency: 25.0, audio_latency: 15.0 }, #GOOD
    { user: user3, ars_total_latency: 40.1, ars_internet_latency: 25, audio_latency: 15.1 }, #FAIR
    ])
  }

  let(:response_body_pop_and_rap) { mock_latency_response([
    { user: user1, ars_total_latency: 1.0, ars_internet_latency: 0.4, audio_latency: 0.6 }, #GOOD
    ])
  }

  let(:response_body_drums_intermediate) { mock_latency_response([
    { user: user1, ars_total_latency: 1.0, ars_internet_latency: 0.4, audio_latency: 0.6 },
    { user: user2, ars_total_latency: 40.0, ars_internet_latency: 25.0, audio_latency: 15.0 }, 
    { user: user3, ars_total_latency: 40.1, ars_internet_latency: 25, audio_latency: 15.1 }, 
    { user: user4, ars_total_latency: 60.0, ars_internet_latency: 30, audio_latency: 30.0 }
    ])
  }

  let(:response_body_drums_violin_expert) { mock_latency_response([
    { user: user2, ars_total_latency: 40.0, ars_internet_latency: 25.0, audio_latency: 15.0 }, 
    { user: user3, ars_total_latency: 40.1, ars_internet_latency: 25, audio_latency: 15.1 }, 
    ])
  }

  let(:response_body_active_within_one_day) { mock_latency_response([
    { user: user4, ars_total_latency: 60.0, ars_internet_latency: 30, audio_latency: 30.0 }, #FAIR
    ])
  }

  let(:response_body_joined_within_one_day) { mock_latency_response([
    { user: user4, ars_total_latency: 60.0, ars_internet_latency: 30, audio_latency: 30.0 }, #FAIR
    { user: user5, ars_total_latency: 60.1, ars_internet_latency: 30.1, audio_latency: 30 }, #HIGH
    ])
  }

  before(:each) do
    User.delete_all

    stub_request(:post, latency_data_uri)
      .with(:headers => {'Accept'=>'*/*', 'Content-Type'=>'application/json', 'User-Agent'=>'Ruby'})
      .to_return( body: response_body, status: 200)
      
    stub_request(:post, latency_data_uri).
      with(
        body: hash_including({ genres: ["pop"]}),
        :headers => {'Accept'=>'*/*', 'Content-Type'=>'application/json', 'User-Agent'=>'Ruby'}
        )
        .to_return( body: response_body_pop, status: 200)
  
    stub_request(:post, latency_data_uri).
      with(
        body: hash_including({ genres: ["pop", "rap"]}),
        :headers => {'Accept'=>'*/*', 'Content-Type'=>'application/json', 'User-Agent'=>'Ruby'}
        )
        .to_return( body: response_body_pop_and_rap, status: 200)

    stub_request(:post, latency_data_uri).
      with(
        body: hash_including({ instruments: [{id: 'drums', proficiency: 2}]}),
        :headers => {'Accept'=>'*/*', 'Content-Type'=>'application/json', 'User-Agent'=>'Ruby'}
        )
        .to_return( body: response_body_drums_intermediate, status: 200)
  
    stub_request(:post, latency_data_uri).
      with(
        body: hash_including({ instruments: [{id: 'drums', proficiency: 3}, {id: 'violin', proficiency: 3}]}),
        :headers => {'Accept'=>'*/*', 'Content-Type'=>'application/json', 'User-Agent'=>'Ruby'}
        )
        .to_return( body: response_body_drums_violin_expert, status: 200)

    stub_request(:post, latency_data_uri).
      with(
        body: hash_including({ active_within_days: 1}),
        :headers => {'Accept'=>'*/*', 'Content-Type'=>'application/json', 'User-Agent'=>'Ruby'}
        )
        .to_return( body: response_body_active_within_one_day, status: 200)

    stub_request(:post, latency_data_uri).
      with(
        body: hash_including({ joined_within_days: 1 }),
        :headers => {'Accept'=>'*/*', 'Content-Type'=>'application/json', 'User-Agent'=>'Ruby'}
        )
        .to_return( body: response_body_joined_within_one_day, status: 200)
  end

  it "when no latency option is selected" do
    opts = { latency_good: false, latency_fair: false, latency_high: false }
    search, latency_data, nextOffset = JamRuby::MusicianFilter.filter(user, remote_ip, opts)
    puts search.results
    puts "===="
    puts latency_data
    puts "===="
    puts nextOffset
    expect(search.results.size).to eq(8)
    expect(latency_data).not_to eq(nil)
    expect(latency_data[0][:audio_latency]).not_to eq(nil)
    expect(latency_data[0][:ars_total_latency]).not_to eq(nil)
    expect(latency_data[0][:ars_internet_latency]).not_to eq(nil)
  end

  it "filter musicians for all latency options" do
    opts = { latency_good: true, latency_fair: true, latency_high: true }
    search, latency_data, nextOffset = JamRuby::MusicianFilter.filter(user, remote_ip, opts)

    expect(search.results.size).to eq(7)
    expect(latency_data).not_to eq(nil)
    expect(latency_data[0][:audio_latency]).not_to eq(nil)
    expect(latency_data[0][:ars_total_latency]).not_to eq(nil)
    expect(latency_data[0][:ars_internet_latency]).not_to eq(nil)

    #sort by latency
    expect(search.results[0][:id]).to eq(user1.id)
    expect(search.results[1][:id]).to eq(user2.id)
    expect(search.results[2][:id]).to eq(user3.id)
    expect(search.results[3][:id]).to eq(user4.id)
    expect(search.results[4][:id]).to eq(user5.id)
    expect(search.results[5][:id]).to eq(user6.id)
    expect(search.results[6][:id]).to eq(user8.id)
    
  end

  it "filter GOOD latency users" do
    opts = { latency_good: true, latency_fair: false, latency_high: false }
    search, latency_data, nextOffset = JamRuby::MusicianFilter.filter(user, remote_ip, opts)
    expect(search.results.size).to eq(3)
  end


  it "filter FAIR latency musicians" do
    opts = { latency_good: false, latency_fair: true, latency_high: false }
    search, latency_data, nextOffset = JamRuby::MusicianFilter.filter(user, remote_ip, opts)
    expect(search.results.size).to eq(2)
  end

  it "filter HIGH latency musicians" do
    opts = { latency_good: false, latency_fair: false, latency_high: true }
    search, latency_data, nextOffset = JamRuby::MusicianFilter.filter(user, remote_ip, opts)
    expect(search.results.size).to eq(2)
  end

  it "filter GOOD and FAIR latency musicians" do
    opts = { latency_good: true, latency_fair: true, latency_high: false }
    search, latency_data, nextOffset = JamRuby::MusicianFilter.filter(user, remote_ip, opts)
    expect(search.results.size).to eq(5)
  end

  it "filter GOOD and HIGH latency musicians" do
    opts = { latency_good: true, latency_fair: false, latency_high: true }
    search, latency_data, nextOffset = JamRuby::MusicianFilter.filter(user, remote_ip, opts)
    expect(search.results.size).to eq(5)
  end

  it "filter GOOD, FAIR and HIGH latency musicians" do
    opts = { latency_good: true, latency_fair: true, latency_high: true }
    search, latency_data, nextOffset = JamRuby::MusicianFilter.filter(user, remote_ip, opts)
    expect(search.results.size).to eq(7)
  end

  it "filter musicians by genres" do
    opts = { latency_good: true, latency_fair: true, latency_high: true, genres: ['pop'] }
    search, latency_data, nextOffset = JamRuby::MusicianFilter.filter(user, remote_ip, opts)
    expect(search.results.size).to eq(3)

    opts = { latency_good: true, latency_fair: true, latency_high: true, genres: ['pop', 'rap'] }
    search, latency_data, nextOffset = JamRuby::MusicianFilter.filter(user, remote_ip, opts)
    expect(search.results.size).to eq(1)
  end

  it "filter musicians by instruments they play" do

    opts = { latency_good: true, latency_fair: true, latency_high: true, instruments: [{value: "drums", label: "Drums"}], proficiency_intermediate: true }
    search, latency_data, nextOffset = JamRuby::MusicianFilter.filter(user, remote_ip, opts)
    expect(search.results.size).to eq(4)

    opts = { latency_good: true, latency_fair: true, latency_high: true, instruments: [{value: "drums", label: "Drums"}, {value: 'violin', label: 'Violin'}], proficiency_expert: true }
    search, latency_data, nextOffset = JamRuby::MusicianFilter.filter(user, remote_ip, opts)
    expect(search.results.size).to eq(2)
  end

  it "filter musicians by days ago that they joined" do
    opts = { latency_good: true, latency_fair: true, latency_high: true, joined_within_days: 1 }
    search, latency_data, nextOffset = JamRuby::MusicianFilter.filter(user, remote_ip, opts)
    expect(search.results.size).to eq(2)
  end

  it "finds user updated_at is within a day ago" do
    opts = { latency_good: true, latency_fair: true, latency_high: true, active_within_days: 1 }
    search, latency_data, nextOffset = JamRuby::MusicianFilter.filter(user, remote_ip, opts)
    expect(search.results.size).to eq(1)
  end

end