require 'spec_helper'

describe 'Band Search Model' do

  let!(:searcher) { FactoryGirl.create(:austin_user) }
  let!(:search) { BandSearch.user_search_filter(searcher) }

  let!(:austin_user) { FactoryGirl.create(:austin_user) }
  let!(:dallas_user) { FactoryGirl.create(:dallas_user) }
  let!(:miami_user) { FactoryGirl.create(:miami_user) }
  let!(:seattle_user) { FactoryGirl.create(:seattle_user) }

  let!(:user_types) { [:austin_user, :dallas_user, :miami_user, :seattle_user] }

  let!(:to_join) { search.search_filter_for_subtype(BandSearch::TO_JOIN) }
  let!(:to_hire) { search.search_filter_for_subtype(BandSearch::TO_HIRE) }

  before(:all) do
    Recording.delete_all
    Band.delete_all
  end

  before(:each) do
    @bands = []
    @bands << @band1 = FactoryGirl.create(:band)
    @bands << @band2 = FactoryGirl.create(:band)
    @bands << @band3 = FactoryGirl.create(:band)
    @bands << @band4 = FactoryGirl.create(:band)

    @bands.each do |bb|
      FactoryGirl.create(:band_musician, :band => bb, :user => FactoryGirl.create(:user))
      (rand(4)+1).downto(1) do |nn|
        FactoryGirl.create(:band_musician, :band => bb, :user => FactoryGirl.create(:user))
      end
    end
  end

  describe "creates search obj" do

    before(:all) do
      User.delete_all
    end
    
    it "associates to user" do
      expect(search.user).to eq(searcher)
      searcher.reload
      expect(searcher.band_search).to eq(search)
    end

    it "sets json" do
      expect(search.search_filter_for_subtype(BandSearch::TO_JOIN)).to eq(BandSearch.json_schema[BandSearch::TO_JOIN])
      expect(search.search_filter_for_subtype(BandSearch::TO_HIRE)).to eq(BandSearch.json_schema[BandSearch::TO_HIRE])
    end

    it "loads all bands by default" do
      search.search_results_page
      expect(search.results.length).to eq(Band.count)
    end

    it "has follower counts" do
      Follow.create(user_id: searcher.id, followable: Band.first)
      search.search_results_page
      expect(search.follow_count(Band.first)).to eq(1)
    end

  end

  describe "generates description" do 

    def check_description(_filter, subtype, key, value, lookup, label)
      _filter[key] = value
      search.search_results_page(subtype, _filter)
      expect(search.description(subtype)).to match(/Current Search: Sort = .*; #{label} = #{lookup[value]}$/)
    end

    it "renders no description for blank" do
      search.search_results_page
      expect(search.description).to eq('')
    end

    it "renders description for sort order" do
      to_join[BandSearch::KEY_TOUR_OPTION] = BandSearch::VAL_YES
      search.search_results_page(BandSearch::TO_JOIN, to_join)
      search.search_results_page
      expect(search.description).to match(/Sort =/)
    end

    context "to_join" do

      it "renders description for band type" do
        check_description(to_join, 
                          BandSearch::TO_JOIN,
                          BandSearch::KEY_BAND_TYPE, 
                          BandSearch::BAND_TYPE_VAL_STRS[1], 
                          BandSearch::BAND_TYPES, 
                          'Band type')
      end

      it "renders description for band status" do
        check_description(to_join, 
                          BandSearch::TO_JOIN, 
                          BandSearch::KEY_BAND_STATUS, 
                          BandSearch::SKILL_VALS[1], 
                          BandSearch::BAND_STATUS, 
                          'Band status')
      end

      it "renders description for concert gigs" do
        check_description(to_join, 
                          BandSearch::TO_JOIN, 
                          BandSearch::KEY_GIGS, 
                          BandSearch::GIG_COUNTS[1], 
                          BandSearch::GIG_LABELS, 
                          'Concert gigs')
      end

      it "renders description for play commitment" do
        check_description(to_join, 
                          BandSearch::TO_JOIN, 
                          BandSearch::KEY_PLAY_COMMIT, 
                          BandSearch::PLAY_COMMIT_VALS[1], 
                          BandSearch::PLAY_COMMITS, 
                          'Play commitment')
      end

      it "renders description for tour option" do
        check_description(to_join, 
                          BandSearch::TO_JOIN, 
                          BandSearch::KEY_TOUR_OPTION, 
                          BandSearch::VAL_YES, 
                          BandSearch::TOUR_OPTIONS, 
                          'Touring options')
      end

      it "renders description for genres" do
        to_join[BandSearch::KEY_GENRES] = [Genre.first.id]
        search.search_results_page(BandSearch::TO_JOIN, to_join)
        expect(search.description).to match(/Current Search: Sort = .*; Genres = #{Genre.first.description}$/)
      end

      it "renders description for instruments" do
        to_join[BandSearch::KEY_INSTRUMENTS] = [{ 'instrument_id' => Instrument.first.id, 'proficiency_level' => 1 }]
        search.search_results_page(BandSearch::TO_JOIN, to_join)
        expect(search.description).to match(/Current Search: Sort = .*; Instruments = #{Instrument.first.description} \(#{BandSearch::INSTRUMENT_PROFICIENCY[1]}\)$/)
      end

    end

    context "to_hire" do
      it "renders description for genres" do
        to_hire[BandSearch::KEY_GENRES] = [Genre.first.id]
        search.search_results_page(BandSearch::TO_HIRE, to_hire)
        expect(search.description(BandSearch::TO_HIRE)).to match(/Current Search: Sort = .*; Genres = #{Genre.first.description}$/)
      end

      it "renders description for band status" do
        check_description(to_hire, 
                          BandSearch::TO_HIRE, 
                          BandSearch::KEY_BAND_STATUS, 
                          BandSearch::BAND_STATUS_VALS[1], 
                          BandSearch::BAND_STATUS, 
                          'Band status')
      end

      it "renders description for concert gigs" do
        check_description(to_hire, 
                          BandSearch::TO_HIRE, 
                          BandSearch::KEY_GIGS, 
                          BandSearch::GIG_COUNTS[1], 
                          BandSearch::GIG_LABELS, 
                          'Concert gigs')
      end

      it "renders description for performance samples" do
        check_description(to_hire, 
                          BandSearch::TO_HIRE, 
                          BandSearch::KEY_PERF_SAMPLES, 
                          BandSearch::PERF_SAMPLES_VALS[1], 
                          BandSearch::PERF_SAMPLES, 
                          'Performance samples')
      end

      it "renders description max cost" do
        to_hire[BandSearch::KEY_HIRE_MAX_COST] = 100
        search.search_results_page(BandSearch::TO_HIRE, to_hire)
        expect(search.description(BandSearch::TO_HIRE)).to match(/Current Search: Sort = .*; Maximum gig cost = \$100$/)
      end

      it "renders description free gigs" do
        to_hire[BandSearch::KEY_HIRE_FREE] = 1
        search.search_results_page(BandSearch::TO_HIRE, to_hire)
        expect(search.description(BandSearch::TO_HIRE)).to match(/Current Search: Sort = .*; Bands playing free gigs$/)
      end

    end

  end

  describe "filtering by keys" do 
    
    let!(:band) { Band.first }

    context 'all search keys' do 

      let!(:filter) { to_join }

      it "filters by gigs" do
        band.update_attribute(:concert_count, BandSearch::GIG_COUNTS[2])
        filter[BandSearch::KEY_GIGS] = BandSearch::GIG_COUNTS[2]
        search.search_results_page(BandSearch::TO_JOIN, filter)
        expect(search.results.length).to eq(1)
        expect(search.results[0].id).to eq(band.id)
      end

      it "filters by genre" do
        pending
        band_id = band.id
        filter[BandSearch::KEY_GENRES] = [band_id]
        search.search_results_page(BandSearch::TO_JOIN, filter)
        expect(search.results.length).to eq(Band.all.map(&:genres).flatten.select { |bb| bb.id == band_id }.count)
      end

      it "filters by band_type" do
        band.update_attribute(:band_type, BandSearch::BAND_TYPE_VAL_STRS[1])
        filter[BandSearch::KEY_BAND_TYPE] = BandSearch::BAND_TYPE_VAL_STRS[1]
        search.search_results_page(BandSearch::TO_JOIN, filter)
        expect(search.results.length).to eq(1)
        expect(search.results[0].id).to eq(band.id)
      end

      it "filters by instruments" do
        minst = FactoryGirl.build(:musician_instrument)
        band.musician_instruments << minst
        band.save
        filter[BandSearch::KEY_INSTRUMENTS] = [{'instrument_id' => minst.instrument_id,
                                                 'proficiency_level' => minst.proficiency_level
                                               }]
        search.search_results_page(BandSearch::TO_JOIN, filter)
        expect(search.results.length).to eq(1)
        expect(search.results[0].id).to eq(band.id)

        filter[BandSearch::KEY_INSTRUMENTS] = [{'instrument_id' => minst.instrument_id,
                                                 'proficiency_level' => minst.proficiency_level + 1
                                               }]
        search.search_results_page(BandSearch::TO_JOIN, filter)
        expect(search.results.length).to eq(0)
      end

    end

    context 'to_join' do 

      let!(:filter) { to_join }

      it "sorts by distance" do
        pending "geo features removed"
        bands = Band.all.reverse
        bb = bands.first
        bb.lat, bb.lng = austin_geoip[:geoiplocation].latitude, austin_geoip[:geoiplocation].longitude
        bb.save!
        bb = bands.second
        bb.lat, bb.lng = dallas_geoip[:geoiplocation].latitude, dallas_geoip[:geoiplocation].longitude
        bb.save!
        bb = bands.third
        bb.lat, bb.lng = miami_geoip[:geoiplocation].latitude, miami_geoip[:geoiplocation].longitude
        bb.save!
        bb = bands.fourth
        bb.lat, bb.lng = seattle_geoip[:geoiplocation].latitude, seattle_geoip[:geoiplocation].longitude
        bb.save!

        filter[BandSearch::KEY_SORT_ORDER] = BandSearch::SORT_VALS[0]
        search.search_results_page(BandSearch::TO_JOIN, filter)
        expect(search.results.length).to eq(Band.count)
        expect(search.results.first.id).to eq(bands.first.id)
        expect(search.results.second.id).to eq(bands.second.id)
        expect(search.results.third.id).to eq(bands.third.id)
        expect(search.results.fourth.id).to eq(bands.fourth.id)
      end

      it "filters by play commitment" do
        band.update_attribute(BandSearch::KEY_PLAY_COMMIT, BandSearch::PLAY_COMMIT_VALS[1].to_i)
        filter[BandSearch::KEY_PLAY_COMMIT] = BandSearch::PLAY_COMMIT_VALS[1]
        search.search_results_page(BandSearch::TO_JOIN, filter)
        expect(search.results.length).to eq(1)
        expect(search.results[0].id).to eq(band.id)
      end

      it "filters by tour option" do
        band.update_attribute(BandSearch::KEY_TOUR_OPTION, true)
        filter[BandSearch::KEY_TOUR_OPTION] = BandSearch::VAL_YES
        search.search_results_page(BandSearch::TO_JOIN, filter)
        expect(search.results.length).to eq(1)
        expect(search.results[0].id).to eq(band.id)
      end

    end


    context 'to_hire' do 
      
      let!(:filter) { to_hire }

      it "filters by free gigs" do
        band.update_attribute(BandSearch::KEY_HIRE_FREE, true)
        filter[BandSearch::KEY_HIRE_FREE] = BandSearch::VAL_YES
        search.search_results_page(BandSearch::TO_HIRE, filter)
        expect(search.results.length).to eq(1)
        expect(search.results[0].id).to eq(band.id)
      end

      it "filters by max cost" do
        band.update_attribute(:gig_minimum, 10)
        filter[BandSearch::KEY_HIRE_MAX_COST] = 5
        search.search_results_page(BandSearch::TO_HIRE, filter)
        expect(search.results.length).to eq(0)

        filter[BandSearch::KEY_HIRE_MAX_COST] = 15
        search.search_results_page(BandSearch::TO_HIRE, filter)
        expect(search.results.length).to eq(1)
      end

      it "filters by perform samples" do
        filter[BandSearch::KEY_PERF_SAMPLES] = BandSearch::VAL_YES
        search.search_results_page(BandSearch::TO_HIRE, filter)
        expect(search.results.length).to eq(0)

        filter[BandSearch::KEY_PERF_SAMPLES] = BandSearch::VAL_NO
        search.search_results_page(BandSearch::TO_HIRE, filter)
        expect(search.results.length).to eq(Band.count)

        ps = PerformanceSample.new
        ps.player = band
        ps.service_type = 'youtube'
        ps.service_id = 'abc123'
        ps.save
        # PerformanceSample.create(player: band, service_type: 'youtube', service_id: 'abc123')
        filter[BandSearch::KEY_PERF_SAMPLES] = BandSearch::VAL_YES
        search.search_results_page(BandSearch::TO_HIRE, filter)
        expect(search.results.length).to eq(1)
        expect(search.results[0].id).to eq(band.id)
      end

    end

  end

end
